What's the best way to sort an optional String Array of "full names"
let unordered:[String?] = [
"Zach Appletree",
"Nancy Crabtree",
"Bill",
nil,
"Bonny Appletree",
"Zach Johnson",
"Paul Brandon"
]
let sortedArray = unordered.sorted(by: { } )
CodePudding user response:
PersonNameComponents
is not Comparable
unless you define conformance yourself.
E.g.
unordered
.lazy
.compactMap { $0.flatMap(PersonNameComponentsFormatter().personNameComponents) }
.sorted()
extension PersonNameComponents: Comparable {
public static func < (components0: Self, components1: Self) -> Bool {
var fallback: Bool {
[\PersonNameComponents.givenName, \.middleName].contains {
Optional(components0[keyPath: $0], components1[keyPath: $0])
.map { $0.lowercased().isLessThan($1.lowercased(), whenEqual: false) }
?? false
}
}
switch (
components0.givenName?.lowercased(), components0.familyName?.lowercased(),
components1.givenName?.lowercased(), components1.familyName?.lowercased()
) {
case let (
_, familyName0?,
_, familyName1?
):
return familyName0.isLessThan(familyName1, whenEqual: fallback)
case (
_, let familyName0?,
let givenName1?, nil
):
return familyName0.isLessThan(givenName1, whenEqual: fallback)
case (
let givenName0?, nil,
_, let familyName1?
):
return givenName0.isLessThan(familyName1, whenEqual: fallback)
default:
return fallback
}
}
}
public extension Comparable {
/// Like `<`, but with a default for the case when `==` evaluates to `true`.
func isLessThan(
_ comparable: Self,
whenEqual default: @autoclosure () -> Bool
) -> Bool {
self == comparable
? `default`()
: self < comparable
}
}
public extension Optional {
/// Exchange two optionals for a single optional tuple.
/// - Returns: `nil` if either tuple element is `nil`.
init<Wrapped0, Wrapped1>(_ optional0: Wrapped0?, _ optional1: Wrapped1?)
where Wrapped == (Wrapped0, Wrapped1) {
self = .init((optional0, optional1))
}
/// Exchange two optionals for a single optional tuple.
/// - Returns: `nil` if either tuple element is `nil`.
init<Wrapped0, Wrapped1>(_ optionals: (Wrapped0?, Wrapped1?))
where Wrapped == (Wrapped0, Wrapped1) {
switch optionals {
case let (wrapped0?, wrapped1?):
self = (wrapped0, wrapped1)
default:
self = nil
}
}
}
CodePudding user response:
Use a compactMap(_:)
https://developer.apple.com/documentation/swift/sequence/2950916-compactmap
let unordered:[String?] = [
"Zach Appletree",
"Nancy Crabtree",
"Bill",
nil,
"Bonny Appletree",
"Zach Johnson",
"Paul Brandon"
]
let sortedArray = unordered.compactMap { $0 }.sorted()
print(sortedArray)