Explanation of sorted(by:) in Swift - swift

I am a little confused regarding the logic behind the sorted(by:) function in Swift (it was sort() in Swift 2). Take the code below for instance...how does the return type bool yield in the reverse ordering of the numbers?
let aBunchOfNumbers = [1,2,3,4,5,6,7,8,9,10]
let reverseSortClosure: (Int, Int) -> Bool = {
(numberOne: Int, numberTwo: Int) -> Bool in
if numberOne < numberTwo {
return true
}
return false
}
aBunchOfNumbers.sorted(by: reverseSortClosure)

(sort(_:) was renamed sorted(by:) since Swift 3)
From the docs:
https://docs.swift.org/swift-book/LanguageGuide/Closures.html#ID95
The sorted(by:) method accepts a closure that takes two arguments of the same type as the array’s contents, and returns a Bool value to say whether the first value should appear before or after the second value once the values are sorted. The sorting closure needs to return true if the first value should appear before the second value, and false otherwise.
That is, the type class for the function that sorted() accepts looks like (T, T) -> Bool, where T is the type of the inout array you want to sort. The function returns true IF the first value of the function should appear before the second value. Swift uses this function to order the list you pass in.

In Swift 2 the sort() method needs to be used as an extension of your array. aBunchOfNumbers.sort(reverseSortClosure) and if you want to reverse it you have to use >.
let aBunchOfNumbers = [1,2,3,4,5,6,7,8,9,10]
let reverseSortClosure: (Int, Int) -> Bool = {
(lhs, rhs) -> Bool in
return lhs > rhs
}
let reversed = aBunchOfNumbers.sort(reverseSortClosure) // [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
You can also simplify your code as follow:
let reversed = aBunchOfNumbers2.sort(>)

The sort method is sorting the array, so the method needs to know what value goes first, second, third, etc. The value that goes first is the value that is true, and the value which goes second is false. That is why the sort method returns in a bool. Also, your code is really complicated and not at all swifty. This does the same thing, just a lot faster.
let aBunchOfNumbers = [1,2,3,4,5,6,7,8,9,10]
aBunchOfNumbers.sort({
$0 > $1 })
Don't be worried if you're not getting closures at first. They are difficult to understand and the syntax is somewhat unique to swift.
Hope this helps

Perhaps you are learning about closures, but you don't need one here. The sort() function takes a second argument that is a function to compare two values - the function returns true if its first argument appears before the second argument.
In your case, the array contains Int - there is already a perfectly good function to compare Ints - it is >. Use it like this:
1> let result = [1,2,3,4].sort(>)
result: [Int] = 4 values {
[0] = 4
[1] = 3
[2] = 2
[3] = 1
}

Related

In Swift what does Element mean when writing an extension on Array?

What does Element mean when writing an extension on Array?
like in this example:
extension Array {
func reduce<T>(_ initial: T, combine: (T, Element) -> T) -> T {
var result = initial
for x in self {
result = combine(result, x)
}
return result
}
}
The combine parameter is a function which takes a parameter of type T and Element. The Element is the actual Element of/in the array.
For example, this is an array of Int elements:
let arr = [1,2,5,77]
In reduce, initial is of type T. This is the staring value for the mapping you are about to perform.
In combine, T is like your starting value for each subsequent step of combing the next Element to produce another value of type T which will be used as the next T in combine, and so and so forth until the entire array has been processed.
If you were using a default use of reduce such as:
arr.reduce(0, +)
You can see that in this case, T and Element would both be of the same type, Int.
However, I could have a custom object that the array is of, and my combine is defining how to get the running total. If you had something like this:
struct Thing {
var val1: String
var val2: Int
}
let thingArray = //...define some Things in an array
You could use reduce and define your own combine function to return the sum of all the val2 values. In this case, T would be an Int, and Element would be Thing.

Why does Xcode report "Variable 'tuple.0' used before being initialized" after I've assigned all elements of a Swift tuple?

I want to assign the 3 numbers in an array to the 3 elements of a tuple using a for loop. The following function seems to do the trick, but Xcode errors as soon as I try to reference the (seemingly) fully assigned tuple. Am I doing something wrong?
typealias Triple = (Int, Int, Int)
func createTuple() -> Triple
{
var tuple: Triple
let r = [8, 6, 3]
for i in 0..<r.count {
switch(i) {
case 0: tuple.0 = r[i]
case 1: tuple.1 = r[i]
case 2: tuple.2 = r[i]
default : break
}
}
return tuple // Xcode says "Variable 'tuple.0' used before being initialized
}
The problem of determining whether a variable can be guaranteed to have been assigned or not is not decidable for the general case. This can be proven by a transformation on the halting problem. If you want to know more about that, I suggest you post a question on the Computer Science stack exchange site.
The Swift compiler approximates the solution to this problem by handling specific cases. Your case is not one of those handled by the Swift compiler (yet)?
If you just want to assign the triple, you can do this:
typealias Triple = (Int, Int, Int)
func createTriple() -> Triple {
return (8, 6, 3)
}
If you want to assign it from an array, it's a lot simpler without the loop and switch (for the case of just 3 components)
typealias Triple = (Int, Int, Int)
func createTriple(from array: [Int]) -> Triple {
guard array.count > 3 else {
fatalError("Can't create a triple from less than 3 elements")
}
return (array[0], array[1], array[2])
}
Although your code covers all three elements of the tuple, Xcode can't be certain that this is true. Between the loop and the switch, Xcode can't be certain that you're actually assigning to each element in tuple. Maybe the loop won't run enough times, or maybe the switch won't hit every case. You can see that they're all covered, but Xcode isn't quite sure.
You should either (a) assign default values to tuple, or (b) if defaults don't make sense, change Triple to contain three optional values, i.e.
typealias Triple = (Int?, Int?, Int?)

Tuple and Function Argument in Swift

In Swift, how is tuple related to function argument?
In the following two examples the function returns the same type even though one takes a tuple while the other takes two arguments. From the caller standpoint (without peeking at the code), there is no difference whether the function takes a tuple or regular arguments.
Is function argument related to tuple in some ways?
e.g.
func testFunctionUsingTuple()->(Int, String)->Void {
func t(x:(Int, String)) {
print("\(x.0) \(x.1)")
}
return t
}
func testFuncUsingArgs()->(Int, String)->Void {
func t(x:Int, y:String) {
print("\(x) \(y)")
}
return t
}
do {
var t = testFunctionUsingTuple()
t(1, "test")
}
do {
var t = testFuncUsingArgs()
t(1, "test")
}
There is also inconsistencies in behavior when declaring tuple in function argument in a regular function (rather than a returned function):
func funcUsingTuple(x:(Int, String)) {
print("\(x.0) \(x.1)")
}
func funcUsingArgs(x:Int, _ y:String) {
print("\(x) \(y)")
}
// No longer works, need to call funcUsingTuple((1, "test")) instead
funcUsingTuple(1, "test")
funcUsingArgs(1, "test3")
UPDATED:
Chris Lattner's clarification on tuple:
"x.0” where x is a scalar value produces that scalar value, due to odd
behavior involving excessive implicit conversions between scalars and
tuples. This is a bug to be fixed.
In "let x = (y)”, x and y have the same type, because (x) is the
syntax for a parenthesis (i.e., grouping) operator, not a tuple
formation operator. There is no such thing as a single-element
unlabeled tuple value.
In "(foo: 42)” - which is most commonly seen in argument lists -
you’re producing a single element tuple with a label for the element.
The compiler is currently trying hard to eliminate them and demote
them to scalars, but does so inconsistently (which is also a bug).
That said, single-element labeled tuples are a thing.
Every function takes exactly one tuple containing the function's arguments. This includes functions with no arguments which take () - the empty tuple - as its one argument.
Here is how the Swift compiler translates various paren forms into internal representations:
() -> Void
(x) -> x
(x, ...) -> [Tuple x ...]
and, if there was a tuple? function, it would return true on: Void, X, [Tuple x ...].
And here is your proof:
let t0 : () = ()
t0.0 // error
let t1 : (Int) = (100)
t1.0 -> 100
t1.1 // error
let t2 : (Int, Int) = (100, 200)
t2.0 -> 100
t2.1 -> 200
t2.2 // error
[Boldly stated w/o a Swift interpreter accessible at the moment.]
From AirSpeedVelocity
But wait, you ask, what if I pass something other than a tuple in?
Well, I answer (in a deeply philosophical tone), what really is a
variable if not a tuple of one element? Every variable in Swift is a
1-tuple. In fact, every non-tuple variable has a .0 property that is
the value of that variable.4 Open up a playground and try it. So if
you pass in a non-tuple variable into TupleCollectionView, it’s legit
for it to act like a collection of one. If you’re unconvinced, read
that justification again in the voice of someone who sounds really
confident.
Remember the 'philosophical tone' as we've reached the 'I say potato; your say potato' phase.
A function in Swift takes a tuple as parameter, which can contain zero or more values. A parameterless function takes a tuple with no value, a function with one parameter takes a tuple with 1 value, etc.
You can invoke a function by passing parameters individually, or by grouping them into an immutable tuple. For example, all these invocations are equivalent:
do {
let t1 = testFunctionUsingTuple()
let t2 = testFuncUsingArgs()
let params = (1, "tuple test")
t1(params)
t1(2, "test")
t2(params)
t2(3, "test")
}

Values accepted in a tuple in swift

I am a completely newbie in swift and in functional Programming.
My silly question is the following:
Can a tuple return a set of functions?
Is it a function like that accepted?
someFunction(param: Bool) -> ((Int) -> Int, (Float) ->Float) -> Double)
Thanks for your reply
You can have a tuple of any type, and functions are types, so you can have tuples of functions.
For example, here’s a 2-tuple of two functions, one that takes two Ints and returns an Int, and one that takes two Doubles and returns a Double:
// a 2-tuple of the addition functions for ints and doubles
let tupleOfFunctions: ((Int,Int)->Int, (Double,Double)->Double) = (+,+)
When you say, “can a tuple return a set of functions?”, I’m guessing you mean, “can a function return a tuple of functions?”. And the answer is also yes:
func returnTwoFunctions(param: Bool) -> ((Int,Int)->Int, (Double,Double)->Double) {
// use the argument to drive whether to return some addition
// or some subtraction functions
return param ? (+,+) : (-,-)
}
Your example, though, is a bit scrambled – if you added a func keyword to the front, it’d be a function declaration, but you’ve got mismatched parentheses. What it looks most like is a function (someFunction) that takes one boolean argument, and returns a function that itself takes two functions and returns a double:
func someFunction(param: Bool) -> (Int->Int, Float->Float) -> Double {
let i = param ? 1 : 2
// this declares and returns a function that itself takes two functions,
// and applies them to pre-determined number
return { f, g in Double(g(Float(f(i)))) }
}
// h is now a function that takes two functions and returns a double
let h = someFunction(false)
// ~ and + are two unary functions that operate on ints and floats
h(~,+) // returns -3.0 (which is +(~2) )
Whether this is what you were intending, and whether you have a use-case for this kind of function, I’m not sure...

Swift: How to better format the output when using println with a tuple?

I have defined this function:
func need_rebalance() -> (Bool, RebalanceStrategy) {
}
where RebalanceStrategy is an enum type
enum RebalanceStrategy: String {
case LeftRight = "LeftRight"
case RightLeft = "RightLeft"
}
When I tried to print it this way,
println("Need rebalance? \(self.need_rebalance())")
I got output like this:
Need rebalance? (false, (Enum Value))
My questions are:
1) Is there an easy to extract a value from a tuple? (Hopefully something similar to python e.g. self.need_rebalance()[1]. Apparently this syntax does not work in swift because tuple does not support subscript())
2) How can I print the raw value of enum instead of having (Enum Value)?
I am using XCode6 Beta5
There's a way to extract the value using tuple indexes, but it's not nice, it involves reflect:
let tuple = self.need_rebalance()
let reflection = reflect(tuple)
reflection[0].1.value // -> true
reflection[1].1.value // -> RebalanceStrategy.?
Also, if your tuple members are not named:
let tuple = self.need_rebalance()
tuple.0 // -> true
tuple.1 // -> RebalanceStrategy.?
To access the raw value in an enum:
RebalanceStrategy.LeftRight.toRaw()
Use .0, .1 and so on to get the respective value from an unnamed tuple.
To get the raw value of the enum, use .toRaw()
var tuple = self.need_rebalance()
println("Need rebalance? \(tuple.0),\(tuple.1.toRaw())")
Better still, use a named tuple like this:
var tuple : (boolValue : Bool, enumValue :RebalanceStrategy) = self.need_rebalance()
println("Need rebalance? \(tuple.boolValue),\(tuple.enumValue.toRaw())")