Swift: reverse(), sort() and sorted() explained

This is a brief exploration of three related but different Swift algorithms: reverse(), sort() and sorted().

Reverse

You can reverse() any type that adopts the CollectionType protocol, which includes String, Array and Dictionary. The results when reverse() is used on an array are predictable, the array is reversed in order, but a reversed string is returned as an array of Characters and a Dictionary is returned as an array of tuples. Not only this, but because order has no meaning to a dictionary, depending as it does on keys and values, the reversed version will not necessarily return the results you are expecting.
/// Return an `Array` containing the elements of `source` in reverse
/// order.
func reverse<C : CollectionType where C.IndexType : BidirectionalIndexType>(source: C) -> [C.GeneratorType.Element]

To experiment with the reverse() algorithm try:
println(reverse("Swift"))
println(reverse(["Hello","#Swift","Welcome","Xcode"]))
println(reverse(["Hello":"#Swift","Welcome":"Xcode"]))
As a point of interest, the Array type also has an instance method reverse() that can be used in the following way:
println(["Hello","#Swift","Welcome","Xcode"].reverse())

Sort

The sort() algorithm  uses inout parameters and takes a pointer to an array, or a type that adopts or inherits the MutableCollectionType protocol. These restrictions mean that you cannot sort an instance of the String type and neither can you sort an instance of Dictionary, since they adopt CollectionType but not MutableCollectionType.
func sort<C : MutableCollectionType where C.IndexType : RandomAccessIndexType, C.GeneratorType.Element : Comparable>(inout collection: C)
func sort<T>(inout array: [T], predicate: (T, T) -> Bool)

func sort<T : Comparable>(inout array: [T])

func sort<C : MutableCollectionType where C.IndexType : RandomAccessIndexType>(inout collection: C, predicate: (C.GeneratorType.Element, C.GeneratorType.Element) -> Bool)

To implement sort() do the following:
var unsorted = ["Hello","#Swift","Welcome","Xcode"] // must be mutable
sort(&unsorted)
sort(&unsorted){$0>$1} // reverse sort
        
println(unsorted)

Sorted

The different permutations of the sorted() algorithm accept for the most part the same types as sort().
func sorted<S : SequenceType where S.GeneratorType.Element : Comparable>(source: S) -> [S.GeneratorType.Element]
func sorted<S : SequenceType>(source: S, predicate: (S.GeneratorType.Element, S.GeneratorType.Element) -> Bool) -> [S.GeneratorType.Element]
func sorted<C : MutableCollectionType where C.GeneratorType.Element : Comparable, C.IndexType : RandomAccessIndexType>(source: C) -> C
func sorted<C : MutableCollectionType where C.IndexType : RandomAccessIndexType>(source: C, predicate: (C.GeneratorType.Element, C.GeneratorType.Element) -> Bool) -> C
The main difference being this:
func sorted<S : SequenceType>(source: S, predicate: (S.GeneratorType.Element, S.GeneratorType.Element) -> Bool) -> [S.GeneratorType.Element]
Meaning that we can use sorted() with String and Dictionary instances, because they inherit the SequenceType protocol through adoption of CollectionType. Note: the return types are the same as when using reverse().
let unsorted = "Hello"
let sortedStr = sorted(unsorted){$0 != $1} // returns array of reversed characters

let unsorted = [1:3,2:2]
let sortedDict = sorted(unsorted){a,b in return a.1 < b.1} // sorts based on values, returns array of tuples
To utilise the sorted() algorithm with an array, code can be written like this:
let unsorted = ["Hello","Swift","Welcome","Xcode"]
let sortedArray = sorted(unsorted)
let revSortedArray = sorted(unsorted){$0>$1} // reverse sort
Instead of using inout parameters and mutating a pre-existing instance, sorted() returns an array of elements or a type that adopts the MutableCollectionType protocol.

Endorse on Coderwall

Comments

  1. Hi! Missed [] for dictionary In first example. Should be println(reverse([["Hello":"#Swift"], ["Welcome":"Xcode"]])) instead

    ReplyDelete
    Replies
    1. No... I am wrong. It just do not work in playground beta5, that is why I disappointed.

      Delete
    2. Beta5 just hang up when you try to reverse dictionary. Do you have a radar on that?

      Delete
    3. Thanks for your comments, I've only just had a chance to look at this. You are right about it hanging and not responding in Beta5. I was to be honest surprised that you would be able to reverse a dictionary when I first tried it. I'm not sure that there would be any practical reason to do so, I just recorded it because it worked at the time, and noted that results would be unpredictable.

      The real bug is that the compiler allows you to use reverse but the operation cannot now be performed.

      Delete

Post a Comment