やりたいこと
[2, nil, 3, 1]
をソートして [1, 2, 3, nil]
にしたい。
うまくいかない実装
以下のコードは一見するとうまくいきそうですが期待通りの結果になりません。
let a: [Int?] = [2, nil, 3, 1]
let s = a.sorted { (l, r) -> Bool in
if let l = l, let r = r {
return l < r
}
return false
}
// -> [2, nil, 1, 3]
これは、比較する2つの値のうちどちらかがnilの場合 (例えば 2
と nil
)、順序を入れ替える前も後も false
として判定される、つまり等価であると判定されてしまうため、正しくソートが行われません。
解決策
1. 左右どちらにnilが来たかで返り値を変える
let a: [Int?] = [2, nil, 3, 1]
let s = a.sorted { (l, r) -> Bool in
switch (l, r) {
case (.some(let l), .some(let r)):
return l < r
case (.some, .none):
return true
case (.none, .some):
return false
case (.none, .none):
return false
}
}
// -> [1, 2, 3, nil]
2. nilを最大値だと仮定する
let a: [Int?] = [2, nil, 3, 1]
let s = a.sorted { (l, r) -> Bool in
l ?? .max < r ?? .max
}
// -> [1, 2, 3, nil]
環境
Apple Swift version 5.3.1 (swiftlang-1200.0.41 clang-1200.0.32.8)
Target: x86_64-apple-darwin19.6.0