12

Trying to sort an array in Swift in descending order. This works well

objectArray.sort{ $0.date!.compare($1.date!) == .orderedDescending}

As you can see, I'm force unwrapping the date. I'm looking for another way so that if the date is nil, the object moves to the end of array.

jscs
  • 63,694
  • 13
  • 151
  • 195
CalZone
  • 1,701
  • 1
  • 17
  • 29
  • Can the date ever be `nil`? Does the app crash? If not, consider to declare the `date` property as non-optional. – vadian May 23 '17 at 20:25
  • @vadian Yes, I don't want app crashing for my client. Instead need to handle the nil data from web service properly. – CalZone May 24 '17 at 00:07

2 Answers2

23

Maybe not the cleanest solution, but you can do it in one step with nil-coalescing.

objectArray.sort{ ($0.date ?? .distantPast) > ($1.date ?? .distantPast) }
John Montgomery
  • 6,739
  • 9
  • 52
  • 68
0

Here's an example of how to sort the nil dates to the end of an array.

In the example, movies is an array of type Movie, which has a date property.

let sortedMovies = movies.sorted { (movieA, movieB) -> Bool in

    switch (movieA.date, movieB.date) {
    case (.some, .some):
        return movieA.date! > movieB.date!

    case (.some, .none):
        return true

    case (.none, _):
        return false
    }
}

Here are some extensions for this function, one non-mutating and one mutating, and with a parameter for descending/ascending.

extension Array
{
    func propertySorted<T: Comparable>(_ property: (Element) -> T?, descending: Bool) -> [Element]
    {
        sorted(by: {
            switch (property($0), property($1)) {
            case (.some, .some):
                return descending ? property($0)! > property($1)! : property($0)! < property($1)!

            case (.some, .none):
                return true

            case (.none, _):
                return false
            }
        })
    }

    mutating func propertySort<T: Comparable>(_ property: (Element) -> T?, descending: Bool)
    {
        sort(by: {
            switch (property($0), property($1)) {
            case (.some, .some):
                return descending ? property($0)! > property($1)! : property($0)! < property($1)!

            case (.some, .none):
                return true

            case (.none, _):
                return false
            }
       })
    }
}

Usage:

let movieNames = movies.propertySorted({ $0.name }, descending: false)
let movieDates = movies.propertySorted({ $0.date }, descending: true)

movies.propertySort({ $0.name }, descending: false)
movies.propertySort({ $0.date }, descending: true)

Extension assistance credit to @Sweeper for answer on Generic function to sort array of class by properties

trishcode
  • 3,299
  • 1
  • 18
  • 25