Home > Mobile >  Swift FullName Array Sort
Swift FullName Array Sort

Time:11-09

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)
  • Related