Swift: Can Someone Explain This Syntax 'Numbers.Sort { $0 > $1 }' for Me

Swift: Can someone explain this syntax `numbers.sort { $0 $1 }` for me?

@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.

What does $0 and $1 mean in Swift Closures?

$0 is the first parameter passed into the closure. $1 is the second parameter, etc. That closure you showed is shorthand for:

let sortedNumbers = numbers.sort { (firstObject, secondObject) in 
return firstObject > secondObject
}

Swift - Could someone help me understand how .sorted(by:) works in this example?

The sorted(by:) function takes a closure as its input parameter, where you can define your own sorting function. The function iterates through the array in element pairs.

$0 and $1 are so called anonymous closure parameters, in this case, $0 is the current element and $1 is the next element.

The switch statement checks whether the current or the next element starts with the string that's stored in the searchTerm variable.

The different states of the switch statement define how the elements should be sorted. If both or neither of the elements have the prefix, they are alphabetically sorted. If only one of them has the prefix, the one that has it will come first in the sorted array.

Hope my explanation was sufficient, if not, just tell me what should I clarify in more detail.

What does $0 represent in closures in Swift?

It's a shorthand argument name.

From the Swift 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.”

— Apple Inc. “The Swift Programming Language.”

It helps reduce the verbosity of your code (sometimes at the cost of readability), so you don't have to write out long argument lists when defining closures.

Can somebody explain this stop in syntax in Swift?

The method is declared as:

func enumerateChildNodesWithName(_ name: String,
usingBlock block: (SKNode,
UnsafeMutablePointer<ObjCBool>) -> Void)

The part in your code between { and } is a trailing closure which is the block. node and stop are the parameter names. It can be also written as:

self.enumerateChildNodesWithName(spriteName) {
node: SKNode, stop: UnsafeMutablePointer<ObjCBool> in

See Closures in the Swift Guide.

The stop parameter is a way to stop the enumeration before enumerating all the items. See How to use "enumerateChildNodesWithName" with Swift in SpriteKit? for more information. Basically the only way to use it is setting stop.memory = true to prevent the next item to be enumerated. This is very useful if you are searching through items and you have already found the one you were looking for.

I am not too sure what is going on in this block of swift code. Anyone know how to explain this?

The code you posted is a loop inside another loop (also known as nested loops.)

The outer loop loops through the key/value pairs in a dictionary.

The inner loop loops through the array of integers from the value of each dictionary.

See if you can reason out what the inner code does. It's only a few lines. As Larme suggested, maybe you sould add print statements inside the outer inner loops to log what is happening at each step:

let interestingNumbers = [
"Prime": [2, 3, 5, 7, 11, 13],
"Fibonacci": [1, 1, 2, 3, 5, 8],
"Square": [1, 4, 9, 16, 25]
]

var largest = 0
for (key, numbers) in interestingNumbers {
print("For key \(key) numbers: \(numbers)")
for number in numbers {
print("number: \(number)")
if number > largest {
print("Replacing previous largest value of \(largest) with \(number)")
largest = number
}
}
}

Then run the program and examine the output carefully.

I am not too sure what is going on in this block of swift code. Anyone know how to explain this?

The code you posted is a loop inside another loop (also known as nested loops.)

The outer loop loops through the key/value pairs in a dictionary.

The inner loop loops through the array of integers from the value of each dictionary.

See if you can reason out what the inner code does. It's only a few lines. As Larme suggested, maybe you sould add print statements inside the outer inner loops to log what is happening at each step:

let interestingNumbers = [
"Prime": [2, 3, 5, 7, 11, 13],
"Fibonacci": [1, 1, 2, 3, 5, 8],
"Square": [1, 4, 9, 16, 25]
]

var largest = 0
for (key, numbers) in interestingNumbers {
print("For key \(key) numbers: \(numbers)")
for number in numbers {
print("number: \(number)")
if number > largest {
print("Replacing previous largest value of \(largest) with \(number)")
largest = number
}
}
}

Then run the program and examine the output carefully.

Sort Dictionary by values in Swift

Try:

let dict = ["a":1, "c":3, "b":2]

extension Dictionary {
func sortedKeys(isOrderedBefore:(Key,Key) -> Bool) -> [Key] {
return Array(self.keys).sort(isOrderedBefore)
}

// Slower because of a lot of lookups, but probably takes less memory (this is equivalent to Pascals answer in an generic extension)
func sortedKeysByValue(isOrderedBefore:(Value, Value) -> Bool) -> [Key] {
return sortedKeys {
isOrderedBefore(self[$0]!, self[$1]!)
}
}

// Faster because of no lookups, may take more memory because of duplicating contents
func keysSortedByValue(isOrderedBefore:(Value, Value) -> Bool) -> [Key] {
return Array(self)
.sort() {
let (_, lv) = $0
let (_, rv) = $1
return isOrderedBefore(lv, rv)
}
.map {
let (k, _) = $0
return k
}
}
}

dict.keysSortedByValue(<)
dict.keysSortedByValue(>)

Updated:

Updated to the new array syntax and sort semantics from beta 3. Note that I'm using sort and not sorted to minimize array copying. The code could be made more compact, by looking at the earlier version and replacing sort with sorted and fixing the KeyType[] to be [KeyType]

Updated to Swift 2.2:

Changed types from KeyType to Key and ValueType to Value. Used new sort builtin to Array instead of sort(Array) Note performance of all of these could be slightly improved by using sortInPlace instead of sort



Related Topics



Leave a reply



Submit