When trying the following in the playground, I get the following error:
Cannot invoke 'sort' with an argument list of type '([Int], (Int, Int) -> Bool)'
let stuff = [1, 2, 3]
var sortedStuff = sort(stuff, { (left: Int, right: Int) -> Bool in left < right })
Am I doing something wrong?
-
Wow... Apple still hasn't updated their iBook... I just harassed them about it on Twitter, so hopefully they'll fix it... we'll see.iconoclast– iconoclast10/01/2014 23:39:24Commented Oct 1, 2014 at 23:39
1 Answer 1
sort()
sorts an array in-place:
var stuff = [3, 2, 1]
sort(&stuff, { (left: Int, right: Int) -> Bool in left < right })
println(stuff) // [1, 2, 3]
The first argument of sort()
must be the address of a variable array (and it does not return a value). This causes the (misleading) error message, as you are passing
an array as the first argument.
What you probably want to use is sorted()
, which does not modify the original array and returns a new sorted array:
let stuff = [3, 2, 1]
var sortedStuff = sorted(stuff, { (left: Int, right: Int) -> Bool in left < right })
println(stuff) // [3, 2, 1]
println(sortedStuff) // [1, 2, 3]
The function names have changed in one of the earlier beta releases, as mentioned in release notes
Important Changes, Issues Resolved in Xcode 6 beta 1–3
...
The globalsort
function now mutates its first argument, and a newsorted
function always returns a new collection.
so some tutorials may be out-of-date. The Swift books however are regularly updated, so you might want to download a current version.
As mentioned in the comments, you can shorten the closure notation in various ways:
let sortedStuff = sorted(stuff, { left, right in left < right }) // Inferring type from context
let sortedStuff = sorted(stuff, { 0ドル < 1ドル }) // Shorthand argument names
let sortedStuff = sorted(stuff, <) // Using an operator function
All this is described in detail in the "Closures" chapter of the Swift book.
Update for Swift 2 (Xcode 7): Returning a sorted array is called "sort" again, but it is a (protocol extension) method now instead of a global function:
let stuff = [3, 2, 1]
let sortedStuff = stuff.sort(<)
print(sortedStuff) // [1, 2, 3]
and sorting an array in place has been renamed to "sortInPlace":
var stuff = [3, 2, 1]
stuff.sortInPlace(<)
print(stuff) // [1, 2, 3]
-
Also shorthand:
sort(&stuff) { 0ドル < 1ドル }
andvar sortedStuff = sorted(stuff) { 0ドル < 1ドル }
where $x revers to the left and right by position by index.zaph– zaph08/25/2014 21:05:13Commented Aug 25, 2014 at 21:05 -
Even-shorter-hand:
sort(&stuff, <)
orsorted(stuff, <)
. You can pass a function or method anywhere a closure is expected, and that includes standard library functions and operators.rickster– rickster08/25/2014 22:09:45Commented Aug 25, 2014 at 22:09 -
Also, since the answer isn't 100% clear on this: the reason your code doesn't work is that you're calling
sort
(which returns nothing) instead ofsorted
(which returns an array). The compiler is giving you the wrong error message (it's obliquely trying to tell you that the expected return type of your function call is not the type of the variable you're assigning it to) -- filing a bug would be a good idea.rickster– rickster08/25/2014 22:12:28Commented Aug 25, 2014 at 22:12 -
1@rickster: Assigning the void return value of sort() to a variable causes only a warning. The error is that sort() is called with a (constant) array instead of the address of a variable array. - Thanks to both of you for the feedback, I have tried to improve the answer.Martin R– Martin R08/26/2014 05:07:55Commented Aug 26, 2014 at 5:07