【问题标题】:Sort nil to the end of an array of optional strings将 nil 排序到可选字符串数组的末尾
【发布时间】:2018-11-22 01:02:46
【问题描述】:

如果我有一个可选字符串数组,并且我想以 nils 开头的升序对其进行排序,我可以在一行中轻松完成:

["b", nil, "a"].sorted{ $0 ?? "" < $1 ?? "" } // [nil, "a", "b"]

但似乎没有任何类似简单的解决方案可以将 nil 排序到数组的 end。大多数其他简单数据类型都可以轻松完成,例如:

[2, nil, 1].sorted{ $0 ?? Int.max < $1 ?? Int.max } // [1, 2, nil]

对于双打,您可以使用greatestFiniteMagnitude 执行相同的操作,对于日期,您可以使用distantFuture。是否有任何等效的字符串,或任何其他简洁的方式来避免编写一堆混乱的条件?

【问题讨论】:

  • 使用"\u{ffff}" 代替""
  • @holex:如果字符串是“????”又名"\u{1f600}"?这与 "\u{ffff}" 相比如何?它可能会偶然起作用,但我不建议使用“魔法值”。
  • @MartinR,这个想法在这里展示了潜在的 high-end unicode 值,而不是 exact 值 - 但同意有更优雅的解决方案(例如你的)但大多数开发人员无法理解这一点。

标签: arrays swift sorting optional


【解决方案1】:

您可以提供考虑nil 的自定义比较器 大于任何非零值:

let array = ["b", nil, "a", nil]

let sortedArray = array.sorted { (lhs, rhs) -> Bool in
    switch (lhs, rhs) {
    case let(l?, r?): return l < r // Both lhs and rhs are not nil
    case (nil, _): return false    // Lhs is nil
    case (_?, nil): return true    // Lhs is not nil, rhs is nil
    }
}

print(sortedArray) // [Optional("a"), Optional("b"), nil, nil]

这适用于任何可选的可比较元素数组,并避免 “神奇的大”值的使用。比较器可以实现 作为一个通用函数:

func compareOptionalsWithLargeNil<T: Comparable>(lhs: T?, rhs: T?) -> Bool {
    switch (lhs, rhs) {
    case let(l?, r?): return l < r // Both lhs and rhs are not nil
    case (nil, _): return false    // Lhs is nil
    case (_?, nil): return true    // Lhs is not nil, rhs is nil
    }
}

print(["b", nil, "a", nil].sorted(by: compareOptionalsWithLargeNil))
// [Optional("a"), Optional("b"), nil, nil]

print([2, nil, 1].sorted(by: compareOptionalsWithLargeNil))
// [Optional(1), Optional(2), nil]

print([3.0, nil, 1.0].sorted(by: compareOptionalsWithLargeNil))
// [Optional(1.0), Optional(3.0), nil]

print([Date(), nil, .distantPast, nil, .distantFuture].sorted(by: compareOptionalsWithLargeNil))
// [Optional(0000-12-30 00:00:00 +0000), Optional(2018-11-22 13:56:03 +0000),
//  Optional(4001-01-01 00:00:00 +0000), nil, nil]

【讨论】:

  • 为什么选择这个名字WithLargeNil
  • @Carpsen90:因为它认为 nil 比任何其他值都更大,我想不出更好的名字:)
【解决方案2】:

一个nil 与另一个没有区别。因此,如果您有一个工作解决方案碰巧按您的意愿排序,除了 nil 条目在开始时结束,请使用它,然后删除 nil 条目并将相同数量的 nil 条目附加到末尾。

例子:

    var arr : [String?] = [nil, "b", nil, "a", nil]
    arr = arr.sorted{ $0 ?? "" < $1 ?? "" }
    if let ix = arr.firstIndex(where: {$0 != nil}) {
        arr = arr.suffix(from: ix) + Array(repeating: nil, count: ix)
    }
    // [Optional("a"), Optional("b"), nil, nil, nil]

【讨论】:

  • arr 已经是var,所以arr.sort { ... } 而不是arr = arr.sorted{ ... }
【解决方案3】:

您的Int 示例提供了一个线索。如果我们有一个最大字符串值,我们可以将其插入。

这适用于仅包含字母字符的字符串:

let maxString = "~"
["b", nil, "a"].sorted{ $0 ?? maxString < $1 ?? maxString }

或者简单地说:

["b", nil, "a"].sorted{ $0 ?? "~" < $1 ?? "~" }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-12-09
    • 2014-11-12
    • 2014-03-06
    • 2014-08-09
    • 2017-09-29
    • 2022-12-11
    • 2012-12-17
    相关资源
    最近更新 更多