Brandon Cornelio
Brandon Cornelio

Reputation: 353

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

This piece of code sorts an array of strings by placing strings with a specific prefix 'searchTerm' at the beginning of the array, and strings that don't have that prefix at the end. Can someone explain how this function works? I'm new at developing in Swift if you couldn't already tell, so please keep the explanation as SIMPLE as possible. Thank you!

stringArray = stringArray.sorted(by: {
    switch ($0.hasPrefix(searchTerm), $1.hasPrefix(searchTerm) {
        case (true, true): return $0 < $1 ;
        case (true, false): return true ;
        case (false, true): return false ;
        case (false, false): return $0 < $1
    }
})

Upvotes: 3

Views: 386

Answers (4)

Abizern
Abizern

Reputation: 150685

The sorted method you are using runs through the array sorting the items according to the criteria you provide in the block. This block needs to return true if one item ($0) should be ordered before the other ($1)

Since you are sorting first on if there is a prefix before the value of the string the comparison is being made like this:

switch ($0.hasPrefix(searchTerm), $1.hasPrefix(searchTerm) {
    case (true, true): return $0 < $1 ; // If both items have the prefix, just sort them the way strings are normally sorted
    case (true, false): return true ; // Since the first item has a prefix and the second does not, it should appear before the second one, so return true.
    case (false, true): return false ; // Since the second item has a prefix, and the first one does not, the first item should be sorted after the second, so return false
    case (false, false): return $0 < $1 // Since neither items have a prefix, just sort them the way strings are normally sorted.
}

An alternative way to do this which might be clearer:

array.sorted { (first, second) -> Bool in
    switch (first.hasPrefix("p"), second.hasPrefix("p")) {
    case (true, true), (false, false): return first < second
    case (true, false): return true
    case (false, true): return false
    }
}

Upvotes: 3

Alexander
Alexander

Reputation: 63369

sorted(by:) lets you specify your own sorting criteria. It performs the sorting by repeatedly asking you how certain elements compare to each other, by running the closure you gave it and passing in the elements as parameters.

This closure comes down to four possible cases:

  • case (true, true): return $0 < $1

    If both $0 and $1 start with searchTerm, then the ordering between them is decided by regular string comparison ($0 < $1)

  • case (true, false): return true

    If $0 starts with searchTerm, but $1 doesn't, then $0 should come before $1

  • case (false, true): return false

    If $0 starts with searchTerm, but $1 doesn't, then $1 should come after $0

  • case (false, false): return $0 < $1

    If neither $0 nor $1 start with searchTerm, then the ordering between them is decided by regular string comparison ($0 < $1)

Upvotes: 1

Elan Hamburger
Elan Hamburger

Reputation: 2177

stringArray = stringArray.sorted(by: {

Here, you are reassigning stringArray to be the sorted version of itself. The inclusion of the by parameter indicates to Swift that you would like it to use your own sorting order instead of the default one (in this case, things that begin with "searchTerm" come before anything else).

To describe your sorting order, you use a comparison function -- a piece of code that takes two elements from your array and compares them. Let's call these elementA and elementB. If elementA should come before elementB, your code should return true. If elementB should come before elementA, your code should return false. By using your code to determine which elements come before other elements, Swift can sort your array based on this specification.

switch ($0.hasPrefix(searchTerm), $1.hasPrefix(searchTerm) {

This line takes the two elements ($0 and $1) and checks if they begin with "searchTerm." For each case, the two booleans in the expression indicate if $0 and $1 start with "searchTerm" respectively.

case (true, true): return $0 < $1 ;

Both of these elements start with "searchTerm," so you want to return the natural ordering (i.e. alphabetical ordering). You let Swift use the standard comparison operator, because $0 < $1 will return true if $0 comes before $1 and false otherwise.

case (true, false): return true ;

$0 starts with "searchTerm," but $1 does not. You want $0 to come before $1, so you return true.

case (false, true): return false ;

$0 does not start with "searchTerm," but $1 does. You want $1 to come before $0, so you return false.

case (false, false): return $0 < $1

Neither $0 nor $1 start with "searchTerm", so you use natural ordering again.

Upvotes: 1

David Pasztor
David Pasztor

Reputation: 54755

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.

Upvotes: 2

Related Questions