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 Int
s, Swift can figure out that our val1
and val2
parameters must be Int
s 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
Type Conversion When Using Protocol in Swift
Make Code With Firebase Asynchronous
Try, Try! & Try? What's the Difference, and When to Use Each
How to Silence a Warning in Swift
Swap Rootviewcontroller With Animation
Swift Xcode Index Freezing or Slow
How to Document the Parameters of a Function'S Closure Parameter in Swift 3
How to Access Program Arguments in Swift
Get Button Pressed Id on Swift Via Sender
Programmatically Screenshot | Swift 3, Macos
Is Swiftui Backwards-Compatible With iOS 12.X and Older
Please Help Me Intepret This Code Swift
Swift Firebase Must Be a Non-Empty String and Not Contain '.' '#' '$' '[' or ']'
What Is the Correct Date.Format for Mmm Dd, Yyyy Hh:Mm:Ss A? and How Convert to Dd-Mm-Yyyy Hh:Ii