将nil排序到可选字符串数组的末尾



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

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

但是,似乎没有任何类似的简单解决方案可以将nils排序到数组的。它可以很容易地与大多数其他简单的数据类型一起完成,例如:

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

对于双打,您可以使用greatestFiniteMagnitude进行同样的操作,对于日期,您可以用distantFuture。字符串有什么等价物吗?或者有其他简洁的方法可以避免写一堆乱七八糟的条件词吗?

您可以提供一个考虑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]

一个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]

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

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

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

或者简单地说:

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

最新更新