Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I sort Swift objects by multiple criteria

Tags:

sorting

swift

I have a list of Swift objects that I'd like to get sorted by multiple criteria. The objects in the list are of type DateRange:

class DateRange {
    var from: NSDate?
    var to: NSDate?
}

The list contains many of these objects where some from or to fields are nil. I want to have this list sorted by:

  1. First all objects that have dates
  2. Then objects that have at least one date (either from or to)
  3. And at the very end objects without any

The dates itself don't matter, just their existence. In Ruby I could do this (if the date is nil I set it to a very low date):

date_ranges.sort { |a, b|
  [fix_nil(a.from), fix_nil(a.to)] <=> [fix_nil(b.from), fix_nil(b.to)]
}.reverse

def fix_nil(val)
  val.nil? ? Date.new(0) : val
end

What's the best way to do this with Swift? Thanks in advance.

like image 360
Mattes Dev Avatar asked Sep 30 '22 11:09

Mattes Dev


1 Answers

Seems like it might be a good idea to add a dateCount computed property to your DateRange type. This would be a good time for pattern matching:

extension DateRange {
    // returns the number of non-nil NSDate members in 'from' and 'to'
    var dateCount: Int {
        switch (from, to) {
        case (nil, nil): return 0
        case (nil, _): return 1
        case (_, nil): return 1
        default: return 2
        }
    }
}

Then you can sort your list with a simple closure:

var ranges = [DateRange(nil, nil), DateRange(NSDate(), nil), DateRange(nil, NSDate()), DateRange(nil, nil), DateRange(NSDate(), NSDate())]
ranges.sort { $0.dateCount > $1.dateCount }

If you wanted, you could even make it Comparable with a few more lines:

extension DateRange : Comparable { }
func ==(lhs: DateRange, rhs: DateRange) -> Bool {
    return lhs.dateCount == rhs.dateCount
}
func <(lhs: DateRange, rhs: DateRange) -> Bool {
    return lhs.dateCount > rhs.dateCount
}

This lets you sort your list properly with an operator argument:

ranges.sort(<)
like image 146
Nate Cook Avatar answered Oct 13 '22 00:10

Nate Cook