Search code examples
swiftsortingmethodssyntaxclosures

Sort(by:) method / Need explanation


Came across this new “sort(by:)” method in my study book, without any reasonable explanation for how and why it works, with this for a code example:

var numbers = [1, 2, 5, 3, 7, 4, 6, 9, 8]

let sortClosure = { (a: Int, b: Int) -> Bool in
    return a < b
}

numbers.sort(by: sortClosure)
print(numbers)

With my own research I found that if a (first element of the array) needs to be before b (second element of the array), the closure returns true and sorts the array that way.

But my compiler says return a < b == false and return a > b == true and I can't understand why, because how can 2 be less than 1?

Please, help me to understand what's wrong with my compiler or what I can't understand it's working from the sort(by:) method?


Solution

  • There are various sort algorithm: Bubble Sort, Quicksort, merge sort, etc.
    They have they pros/cons, mostly about : memory use, complexity, etc. In a nutshell: Will it create another full array or more in memory while sorting? Will it takes a lot of time if the array if big? etc.

    In this other StackOverflow question, you might see which algorithm seems to be used, and it seems that the algorithm changed in the past. And tomorrow, the algorithm might change or even adapt (like: if there are less than 1k elements, do sort logic 1, but if there are more, do sort logic 2 because it's less expensive on memory and you have not a lot of RAM currently, etc.)

    But as you want to use the high level method sort(by:), and not implement yourself the algorithm, do not focus on it.

    Just focus on what to do in the closure which is quite simple:

    • you have 2 elements in parameters
    • retrieve from them the infos to compare: be it they raw value, a computed property, another related value you want etc.
    • compare these two values: return true if you want the first parameter to be placed before the second one, false in the other case.

    You can print the value if you want:

    let returnValue = a < b
    print("Comparing \(a) vs \(b) and returning: \(returnValue)")
    return returnValue
    

    In your simple case, you are comparing the raw value which are Int.

    So the full lines of the previous explanation are:

    let valueFromAToCompare = a
    let valueFromBToCompare = b
    return valueFromAToCompare < valueFromBToCompare
    

    Which can obviously be simplified as return a < b.

    If we had structs like that in our array, and you want to sort according to its numbers:

    struct MyStruct {
        let number: Int
        let subNumber: String
    }
    

    The closure would be:

    let valueFromAToCompare = a.number
    let valueFromBToCompare = b.number
    return valueFromAToCompare < valueFromBToCompare
    

    Which can be simplified into: return a.number < b.number.

    But as you can guess, there can be later more complex sort logic: compare the numbers, but if the numbers are equals, then compare the subNumber, hence the closure which can let you put your whole logic:

    if a.number == b.number {
        return a.subNumber < b.subNumber
    } else {
        return a.number < b.number
    }
    

    Of course, it can simplified or written differently, but that's to make the example more comprehensible.