9

First of all, this question is not about "what does $0 mean". I learnt in swift document that $0 is like index.

My question is "How numbers.sort { $0 > $1 } can be used to implement a sort function". I searched for this syntax numbers.sort { $0 > $1 } in some other websites, for example this one. It is apparently not the current version. So I still can't understand what the meaning of it.

print(numbers) //[20, 19, 1, 12]
let sortedNumbers = numbers.sort { $0 > $1 }
print(sortedNumbers) //[20, 19, 12, 1]

Can someone explain this simple piece of code above for me? Like how this simple code $0 > $1 implement the sort function, sorting the numbers from big to small.

I know some about index, and this $0 looks like index, but it only has $0 and $1 two indices. So how can it be used into 4 numbers? According to my knowledge in C++ before, I can't understand the principle in this.

Please make your answer as specific as possible. Thank you!

----------------- Below is edited extra part -------------------

I don't know whether stackoverflow would allow me to edit my question like this, but this extra part is too long, so I can't add it in the comment. @pbodsk @Paul Richter

So the sort() syntax in swift uses quick sort to deal with sort function?

Actually my question is more about "what is the operating principle of sort{$0 > $1}". I know what you mean above, and I think it's similar with what swift 2.1 document says, but your answer is not what I really want to know. Sorry, my English expression is not very good. Let me try another way.

When I learnt C++ before, there are always some documents to explain what a function's operating principle is or how this function (like sort() here) operate in background. Sort() here needs to compare first and second interchange. In C++, it's like

if numbers[1] < numbers[2]{ //just consider this pseudocode
    int k;
    k = numbers[1];
    numbers[1] = numbers[2];
    numbers[2] = k;
}

We can see this process is obvious. In swift, it's like

numbers.sort({(val1: Int, val2: Int) -> Bool in
   return val1 > val2
})

Where is it compared? And how is it interchanged? Does return val1 > val2 automatically compare and interchange these two values and return them? Just this one syntax implement these all 3 processes? How? This is what I really want to know. Sorry again for my poor English expression.

JW.ZG
  • 611
  • 1
  • 7
  • 20
  • you're looking at sorts shorthand syntax... $0 actually represents your left variable and $1 represents your right variable – Dan Beaulieu Jan 14 '16 at 06:14
  • 1
    Possible duplicate of [What does $0 represent in closures in Swift?](http://stackoverflow.com/questions/27491620/what-does-0-represent-in-closures-in-swift) – Cristik Jan 14 '16 at 07:46
  • That's in every introduction to Swift. Look at closures, and then at the various shortcuts for writing closures. – gnasher729 Jan 14 '16 at 14:47
  • @gnasher729 I am learning Swift with *The Swift Programming Language (Swift 2.1)* in iBook. I didn't see explanation of the principle of how this piece of code `numbers.sort { $0 > $1 }` is implemented in the "back" or when it is compiled. – JW.ZG Jan 14 '16 at 16:38
  • 4
    The function passed to `sort` does not *implement* the sorting, it is used to decide whether one element should come before another element in the result (i.e. it "sorts" two elements). It's used by the `sort` function in the same place where a number-sorting function would use `<`. (Incidentally, C++ has an overload of [`std::sort`](http://en.cppreference.com/w/cpp/algorithm/sort) that takes a comparison function as a parameter.) – molbdnilo Jan 14 '16 at 21:19

5 Answers5

31

@the_UB and @moonvader are both right, but I just thought that I would extend the example from @moonvader a bit, just to show you how we end up with $0 > $1

If you look at the example in "The Swift Programming Language" about Closure Expressions you can see that to sort an array you call the sort method which can then take a function as a parameter.

This function must take two parameters and compare them, and then return a boolean.

So if we have this array:

let numbers = [4, 6, 8, 1, 3]

and this method

func sortBackwards(val1: Int, val2: Int) -> Bool {
   print("val1: \(val1) - val2: \(val2)" )
   return val1 > val2
}

We can sort the elements like so:

numbers.sort(sortBackwards) //gives us [8, 6, 4, 3, 1]

The sort method will use our sortBackwards method on each of the elements in the array and compare them.

Here's the output of the print

val1: 6 - val2: 4
val1: 8 - val2: 4
val1: 8 - val2: 6
val1: 1 - val2: 4
val1: 3 - val2: 1
val1: 3 - val2: 4

OK, let's reduce that.

Instead of defining a function, we can add that directly as a parameter to the sort method like so:

numbers.sort({(val1: Int, val2: Int) -> Bool in
   return val1 > val2
})

And we still end up with [8, 6, 4, 3, 1] (how fortunate!)

OK, the next thing we can do is what in "The Swift Programming Language" (the link above) is called "Infering Type From Context". As we call this method on an array of Ints, Swift can figure out that our val1 and val2 parameters must be Ints too, there's no need for us to tell it. So, lets remove the types. That leaves us with:

numbers.sort({val1, val2 in
   return val1 > val2
})

And still the same result.

OK, getting there. The next thing we can do is what in the book is called "Implicit Returns from Single-Expression Closures"

As our comparison can be done in one line there's no need for us to use return. So:

numbers.sort({val1, val2 in val1 > val2})

Still gives us [8, 6, 4, 3, 1]

Finally we're getting to what @moonvader used much much less words to explain :-) namely "Shorthand Argument Names"

As it says in the book:

Swift automatically provides shorthand argument names to inline closures, which can be used to refer to the values of the closure’s arguments by the names $0, $1, $2, and so on.

So, in our example, val1 can be replaced by $0 and val2 can be replaced by $1

Which gives us:

numbers.sort({$0 > $1})

And still we get [8, 6, 4, 3, 1]

We can then continue to use a "Trailing Closure", which means that if the last parameter of a function is a closure, we can add that parameter "outside" the function.

So we end up with:

numbers.sort{$0 > $1}

And the outcome is still [8, 6, 4, 3, 1]

Hope that helps to clarify things.

pbodsk
  • 6,787
  • 3
  • 21
  • 51
3

Here is what all need to know: Sort and Sorted.

To be more specific, Sorting can be two type : Ascending and Descending.

Q - So to do sorting, what do we need?

A - We need two variables to hold two variable(I don't know if it is the correct word)

Hence in this case we have two variable $0 and $1. These both are shorthands to represent left and right variable. Both will help to sort.

">" will do descending.

"<" will do ascending.

Bista
  • 7,869
  • 3
  • 27
  • 55
  • 1
    "sorted" was in Swift 1 and has been deprecated. Now we use "sort" and "sortInPlace". This blog post is obsolete. – Eric Aya Jan 14 '16 at 07:01
3

From developer.apple.com

Shorthand Argument Names

Swift automatically provides shorthand argument names to inline closures, which can be used to refer to the values of the closure’s arguments by the names $0, $1, $2, and so on.

If you use these shorthand argument names within your closure expression, you can omit the closure’s argument list from its definition, and the number and type of the shorthand argument names will be inferred from the expected function type. The in keyword can also be omitted, because the closure expression is made up entirely of its body:

reversed = names.sort( { $0 > $1 } )

Here, $0 and $1 refer to the closure’s first and second String arguments.

moonvader
  • 19,761
  • 18
  • 67
  • 116
  • Thank you, but most part of your answer is what swift 2.1 document says, which I have read many many times. – JW.ZG Jan 14 '16 at 20:42
3

The process of sorting a list consists of repeatedly reordering its elements until nothing remains to be reordered. Now there are many sorting algorithms, but they all do this, in different ways. So then how are elements reordered? By comparing two given elements, and deciding which comes first, and swapping them if needed.

We can separate the overall reordering and swapping parts from the comparison part, and write a sort function that will take care of all the repeated reordering stuff, and just require the caller to specify how to compare two elements. If the list consists of numbers, it's almost always the case that the way to compare them is to just take their value. But suppose the list consists of things a little more complicated, like cars. How do you compare two cars? Well, you could compare them by numerically comparing their top speed. Or their gas mileage. Or price.

But the comparison doesn't have to be numerical. We could compare two cars by actually racing them. We could compare two cars by just saying if one is blue and the other isn't, the blue one is ordered first, and if neither or both are blue they are ordered as they already are.

We could come up with all sorts of ways to compare two cars. And the sorting algorithm could then sort a list of cars, without knowing anything about cars, as long as we the caller just tell it how to compare cars - any two given cars. We just have to express that comparison as an expression that returns a boolean, where if it's true, the first car is ordered before the second one, and if it's false, the first car is ordered after the second one.

Returning to numbers, that's what sort { $0 > $1 } means, in Swift's very concise syntax: "Sort, where if the first element is > the second one, order the first one before the second one."

You asked how it can sort four numbers with only two indices. $0 and $1 are not bound to the four specific elements in the list [20, 19, 1, 12], they are bound to any two given numbers that need to be compared, because the sorting algorithm repeately needs to do this.

There are a few things to note. First, the operator > has to be defined for the kinds of elements you are sorting. In the example the elements are numbers, and > is indeed defined. Second, the sort function specifies that the boolean true orders the first one before the second rather than the other way around, so the comparison function follows that specification. Third, the last evaluated expression is taken as the boolean value to be used. Having these two assumptions beforehand allows the comparison function to be written so concisely.

So if we wanted to sort those cars by racing them, we could write it like this:

cars.sort {
  winner_of_race_between($0, $1) == $0 
  // if the first car beats the second, it is sorted ahead
}

Or exclusive blueness:

cars.sort { //not guaranteed to be valid Swift, just consider this pseudocode
  if(($0.color != Color.blue) && ($1.color == Color.blue) {
    $1
  } else if (($0.color == Color.blue) && ($1.color != Color.blue)) {
    $0
  } else { //leave them in same order
    $0
  }
}
Paul Richter
  • 6,154
  • 2
  • 20
  • 22
-1
extension Array {
    
    public func mySorted(by areInIncreasingOrder: (Element, Element) throws -> Bool) rethrows -> [Element] {
        var newArray: [Element] = self
        if newArray.count <= 1 {
            /// nothing to do
        } else if newArray.count <= 32 { /// 32 ?? 64
            for l in 1..<count {
                for r in (0..<l).reversed() {
                    if try areInIncreasingOrder(newArray[r + 1], newArray[r]) {
                        (newArray[r + 1], newArray[r]) = (newArray[r], newArray[r + 1])
                    } else {
                        break
                    }
                }
            }
        } else {
            /// others sort
        }
        return newArray
    }
    
}

var array: [Int] = [4, 6, 8, 1, 3]
let a1 = array.sorted {
    print("\($0)    \($1)")
    return $0 > $1
}
print("---------")
let a2 = array.mySorted {
    print("\($0)    \($1)")
    return $0 > $1
}

print("==========")

let a1 = array.sorted {
    print("\($0)    \($1)")
    return $0 < $1
}
print("+++++++")
let a2 = array.mySorted {
    print("\($0)    \($1)")
    return $0 < $1
}
craig wang
  • 19
  • 3
  • 2
    `Can someone explain this simple piece of code above for me?` - where is this answered in your post? This answer looks like providing another `sort()` implementation, however it doesn't address the topics from the question. – Cristik Oct 27 '21 at 15:02
  • Sorry I understand wrong – craig wang Oct 27 '21 at 15:44