You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift 可选类型全名字符串数组如何按姓氏排序且nil和单名排在最前

可选全名数组排序的最优实现

排序规则拆解

首先把需求中的排序优先级拆分为3个层级,优先级从高到低如下:

  • 第一优先级:nil值排在最前
  • 第二优先级:非nil的单名(不含空格的字符串)排在nil之后
  • 第三优先级:包含空格的全名,先按姓氏排序,姓氏相同再按名字排序

基础实现

直接在sorted(by:)闭包中实现排序逻辑,适合中小规模数组使用:

let unordered:[String?] = [
"Zach Appletree",
"Nancy Crabtree",
"Bill",
nil,
"Bonny Appletree",
"Zach Johnson",
"Paul Brandon"
]

let sortedArray = unordered.sorted { a, b in
    // 定义元素类型权重,数值越小优先级越高
    func weight(for str: String?) -> Int {
        guard let str = str else { return 0 }
        return str.contains(" ") ? 2 : 1
    }
    
    let weightA = weight(for: a)
    let weightB = weight(for: b)
    
    // 权重不同直接按权重排序
    if weightA != weightB {
        return weightA < weightB
    }
    
    // 都是nil的情况,顺序不影响
    guard let strA = a, let strB = b else { return false }
    
    // 都是单名的情况,直接按字符串自然排序
    if weightA == 1 {
        return strA < strB
    }
    
    // 都是全名,拆分姓和名,过滤多余空格避免异常
    let componentsA = strA.components(separatedBy: .whitespaces).filter { !$0.isEmpty }
    let componentsB = strB.components(separatedBy: .whitespaces).filter { !$0.isEmpty }
    // 异常容错:如果拆分后不足2段,降级为单名排序逻辑
    guard componentsA.count >= 2, componentsB.count >= 2 else {
        return strA < strB
    }
    let lastNameA = componentsA.last!
    let lastNameB = componentsB.last!
    // 先比较姓氏
    if lastNameA != lastNameB {
        return lastNameA < lastNameB
    }
    // 姓氏相同再比较名字
    let firstNameA = componentsA.first!
    let firstNameB = componentsB.first!
    return firstNameA < firstNameB
}

// 输出结果:[nil, "Bill", "Bonny Appletree", "Zach Appletree", "Paul Brandon", "Nancy Crabtree", "Zach Johnson"]
print(sortedArray)

大数组优化实现

如果待排序数组元素较多,可提前预计算每个元素的排序字段,避免排序过程中重复拆分字符串、计算权重,减少O(n log n)量级的重复运算:

extension String {
    // 预提取排序用的元组:(权重, 姓氏, 名字)
    var sortMeta: (weight: Int, lastName: String, firstName: String) {
        if contains(" ") {
            let components = components(separatedBy: .whitespaces).filter { !$0.isEmpty }
            guard components.count >= 2 else {
                return (1, self, self)
            }
            return (2, components.last!, components.first!)
        } else {
            return (1, self, self)
        }
    }
}

let sortedOptimized = unordered
    .map { item -> (weight: Int, lastName: String, firstName: String, origin: String?) in
        guard let item = item else {
            return (0, "", "", nil)
        }
        let meta = item.sortMeta
        return (meta.weight, meta.lastName, meta.firstName, item)
    }
    .sorted { a, b in
        if a.weight != b.weight {
            return a.weight < b.weight
        }
        if a.lastName != b.lastName {
            return a.lastName < b.lastName
        }
        return a.firstName < b.firstName
    }
    .map(\.origin)

内容的提问来源于stack exchange,提问作者justdan0227

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 11:54:04