# Different ways to sort an array of strings in Swift

## Table of Contents

## How to sort an array of strings

There are two ways to sort in Swift, The one that mutates the original array and the one that don't. Both of them shared the same requirement: the element in the collection must conform to Comparable protocol.

Types that conform to Comparable protocol can be compared using the relational operators <, <=, >=, and >. Many types in the standard library, including `String`

, are conform to the Comparable protocol.

### Mutating sort with sort and sort(by:)

`sort()`

and `sort(by:)`

are sort functions that mutate the original array. To use it, call `sort()`

over a mutable array value.

`var students = ["Kofi", "Abena", "Peter", "Kweku", "Akosua"] // <1>`

students.sort()

print(students)

// Prints "["Abena", "Akosua", "Kofi", "Kweku", "Peter"]"

<1> Since `sort()`

is mutating function, you have to declare array as `var`

. Otherwise, you will get the following error.

`Cannot use mutating member on immutable value: 'students' is a 'let' constant`

Change 'let' to 'var' to make it mutable

`sort()`

will use the less-than operator (`<`

) when making a comparison among elements, which result in ascending sort order. To sort in descending order, you need to use `sort(by:)`

method, which allows you to specify a comparison closure that returns true if its first argument should be ordered before its second argument.

`var students = ["Kofi", "Abena", "Peter", "Kweku", "Akosua"]`

students.sort { (lhs: String, rhs: String) -> Bool in

return lhs > rhs

}

// Prints "["Peter", "Kweku", "Kofi", "Akosua", "Abena"]"

### Immutable sort with sorted and sorted(by:)

`sorted()`

and `sorted(by:)`

has the same functionality as `sort()`

and `sort(by:)`

. The only difference is that they return the new sorted elements of the sequence instead of modifying the original array.

`let students = ["Kofi", "Abena", "Peter", "Kweku", "Akosua"] // <1>`

let sortedStudents = students.sorted() // <2>

print(students)

// Prints "["Kofi", "Abena", "Peter", "Kweku", "Akosua"]" <3>

print(sortedStudents)

// Prints "["Abena", "Akosua", "Kofi", "Kweku", "Peter"]" <4>

<1> We can use `let`

here since `sorted()`

and `sorted(by:)`

don't mutate the original array.

<2> We need to declare a new variable to read a sorted result.

<3> The original array doesn't change.

<4> `sorted()`

return a new sorted array.

Like `sort()`

, `sorted()`

use the less-than operator (`<`

) when making a comparison among elements, which result in ascending sort order. You need `sorted(by:)`

if you want to order it differently.

`let students = ["Kofi", "Abena", "Peter", "Kweku", "Akosua"]`

let sortedStudents = students.sorted { (lhs: String, rhs: String) -> Bool in

return lhs > rhs

}

print(sortedStudents)

// Prints "["Peter", "Kweku", "Kofi", "Akosua", "Abena"]"

The sort function is straightforward. You pick the sort method depending on whether you want to mutate the array or not. Let's go through some necessary sort ordering that you might find in day to day job.

Practical Sign in with Apple: Learn everything you need to know about Sign in with Apple to be able to integrate it in your existing app or a new one.

## How to sort array in ascending order

You can use either `sort()`

or `sorted()`

to sort strings in ascending order.

`var students = ["Kofi", "Abena", "Peter", "Kweku", "Akosua"]`

let sortedStudents = students.sorted()

students.sort()

print(students)

// Prints "["Abena", "Akosua", "Kofi", "Kweku", "Peter"]"

print(sortedStudents)

// Prints "["Abena", "Akosua", "Kofi", "Kweku", "Peter"]"

## How to sort array in descending order

You can sort in descending order by specify sorting closure to either `sort(by:)`

or `sorted(by:)`

.

`var students = ["Kofi", "Abena", "Peter", "Kweku", "Akosua"]`

let sortedStudents = students.sorted { (lhs: String, rhs: String) -> Bool in

return lhs > rhs

}

students.sort { (lhs: String, rhs: String) -> Bool in

return lhs > rhs

}

print(students)

// Prints "["Peter", "Kweku", "Kofi", "Akosua", "Abena"]"

print(sortedStudents)

// Prints "["Peter", "Kweku", "Kofi", "Akosua", "Abena"]"

## How to reverse sort order in Swift

You can reverse the array elements using `reverse()`

that mutate the original array or immutable variant, `reversed()`

.

`let students = ["Kofi", "Abena", "Peter", "Kweku", "Akosua"]`

let ascStudents = students.sorted()

let dscStudents = Array(ascStudents.reversed())

print(ascStudents)

// Prints "["Abena", "Akosua", "Kofi", "Kweku", "Peter"]"

print(dscStudents)

// Prints "["Peter", "Kweku", "Kofi", "Akosua", "Abena"]"

## How to sort array alphabetically

Ascending order might not be the order you seek when sorting an array of strings.

Here's an example array of name which contain in both capital case and lower case.

`let students = ["Kofi", "Abena", "Peter", "Kweku", "Akosua", "abena", "bee"]`

let sortedStudents = students.sorted()

print(sortedStudents)

// Prints "["Abena", "Akosua", "Kofi", "Kweku", "Peter", "abena", "bee"]"

As you can see, the sorted result is case sensitive where "Abena" and "abena" are separate apart. In this case, you need more control over comparing methods. Luckily Swift has many build-in comparison methods for you.

`caseInsensitiveCompare(_:)`

will compare two strings ignoring case. This is a shortform of calling `compare(_:options:)`

with `.caseInsensitive`

as the only option.

`let students = ["Kofi", "Abena", "Peter", "Kweku", "Akosua", "abena", "bee"]`

let sortedStudents = students.sorted { (lhs: String, rhs: String) -> Bool in

return lhs.caseInsensitiveCompare(rhs) == .orderedAscending

}

print(sortedStudents)

// Prints "["Abena", "abena", "Akosua", "bee", "Kofi", "Kweku", "Peter"]"

You can also use `compare(_:options:)`

with `.caseInsensitive`

as the only option which yields the same result.

`let students = ["Kofi", "Abena", "Peter", "Kweku", "Akosua", "abena", "bee"]`

let sortedStudents = students.sorted { (lhs: String, rhs: String) -> Bool in

return lhs.compare(rhs, options: .caseInsensitive) == .orderedAscending

}

print(sortedStudents)

// Prints "["Abena", "abena", "Akosua", "bee", "Kofi", "Kweku", "Peter"]"

`caseInsensitiveCompare(_:)`

gives the result we want for this small sample array, but might not be the right method for what we need. In reality, name or string sort is far more complicated than this. In some countries, there might be a use of a diacritic mark, which makes sorting harder.

Let's see what will happen after we add "ábenā" to our students' array. I use "ábenā" as an example to show a case with a diacritic. It might not be a valid name.

`let students = ["Kofi", "Abena", "Peter", "Kweku", "Akosua", "abena", "bee", "ábenā"]`

let sortedStudents = students.sorted { (lhs: String, rhs: String) -> Bool in

return lhs.caseInsensitiveCompare(rhs) == .orderedAscending

}

print(sortedStudents)

// Prints "["Abena", "abena", "Akosua", "ábenā", "bee", "Kofi", "Kweku", "Peter"]"

As you can see, "ábenā" gets separated from "Abena" and "abena". You can specify `.diacriticInsensitive`

option to ignore the diacritic mark, but you can see that the complexity increases and increases as we try to handle more cases.

`let sortedStudents = files.sorted { (lhs: String, rhs: String) -> Bool in`

return lhs.compare(rhs, options: [.diacriticInsensitive, .caseInsensitive]) == .orderedAscending

}

### Do we have to know all language features to be able to sort them?

Luckily, the answer is no. What we really need here is a locale-aware comparison method. Apple provided three locale-aware comparison methods for you. `localizedCompare`

, `localizedCaseInsensitiveCompare`

, and `localizedStandardCompare`

.

`let files = ["Kofi", "Abena", "Peter", "Kweku", "Akosua", "abena", "bee", "ábenā"]`

let sorted = files.sorted()

let compare = files.sorted { (lhs: String, rhs: String) -> Bool in

return lhs.compare(rhs) == .orderedAscending

}

let caseInsensitiveCompare = files.sorted { (lhs: String, rhs: String) -> Bool in

return lhs.caseInsensitiveCompare(rhs) == .orderedAscending

}

let localizedCompare = files.sorted { (lhs: String, rhs: String) -> Bool in

return lhs.localizedCompare(rhs) == .orderedAscending

}

let localizedCaseInsensitiveCompare = files.sorted { (lhs: String, rhs: String) -> Bool in

return lhs.localizedCaseInsensitiveCompare(rhs) == .orderedAscending

}

let localizedStandardCompare = files.sorted { (lhs: String, rhs: String) -> Bool in

return lhs.localizedStandardCompare(rhs) == .orderedAscending

}

**Result:**

sorted | compare | caseInsensitiveCompare | localizedCompare | localizedCaseInsensitiveCompare | localizedStandardCompare |
---|---|---|---|---|---|

Abena | Abena | Abena | abena | Abena | abena |

Akosua | Akosua | abena | Abena | abena | Abena |

Kofi | Kofi | Akosua | ábenā | ábenā | ábenā |

Kweku | Kweku | ábenā | Akosua | Akosua | Akosua |

Peter | Peter | bee | bee | bee | bee |

abena | abena | Kofi | Kofi | Kofi | Kofi |

bee | ábenā | Kweku | Kweku | Kweku | Kweku |

ábenā | bee | Peter | Peter | Peter | Peter |

As you can see, all three locale-aware comparison methods, `localizedCompare`

, `localizedCaseInsensitiveCompare`

, and `localizedStandardCompare`

giving a reasonable sort result.

### There are three locale-aware methods. Which one should I use?

`localizedStandardCompare`

is the one that you should use. The reason is in the next section.

## How to sort file name or string with numbers

If your string contains a number such as `Name2.txt`

, `Name7.txt`

, and `Name25.txt`

, you want it to sort like this:

`Name2.txt`

Name7.txt

Name25.txt

Not this:

`Name2.txt`

Name25.txt

Name7.txt

This is where `localizedStandardCompare`

comes to the rescue. `localizedStandardCompare`

compares strings the same way that Finder does. Which already handles this kind of numeric sorting.

`let files = ["Design final.psd", "untitled01.txt", "untitled1.txt", "design final.psd", "design final(2).psd", "design final final.psd", "design final2.psd", "design final12.psd", "untitled2.txt", "untitled21.txt", "untitled11.txt", "untitled012.txt", "untitled.txt", "Design Final2.psd", "DESIGN final final.psd", "untitled12.psd"]`

let sortedFiles = files.sorted { (lhs: String, rhs: String) -> Bool in

return lhs.localizedStandardCompare(rhs) == .orderedAscending

}

You can achieve similar effect with `compare(_:options:range:locale:)`

passing `.numeric`

option.

`let custom = files.sorted { (lhs: String, rhs: String) -> Bool in `

return lhs.compare(rhs, options: [.numeric], locale: .current) == .orderedAscending

}

There is minor different between `localizedStandardCompare`

and `compare(_:options:range:locale:)`

with `.numeric`

option as you can see in the following result (`untitled01.txt`

and `untitled1.txt`

).

**Result:**

caseInsensitiveCompare | localizedCompare | localizedCaseInsensitiveCompare | localizedStandardCompare | custom |
---|---|---|---|---|

design final final.psd | design final final.psd | design final final.psd | design final final.psd | design final final.psd |

DESIGN final final.psd | DESIGN final final.psd | DESIGN final final.psd | DESIGN final final.psd | DESIGN final final.psd |

design final(2).psd | design final.psd | Design final.psd | design final.psd | design final.psd |

Design final.psd | Design final.psd | design final.psd | Design final.psd | Design final.psd |

design final.psd | design final(2).psd | design final(2).psd | design final(2).psd | design final(2).psd |

design final12.psd | design final12.psd | design final12.psd | design final2.psd | design final2.psd |

design final2.psd | design final2.psd | design final2.psd | Design Final2.psd | Design Final2.psd |

Design Final2.psd | Design Final2.psd | Design Final2.psd | design final12.psd | design final12.psd |

untitled.txt | untitled.txt | untitled.txt | untitled.txt | untitled.txt |

untitled01.txt | untitled01.txt | untitled01.txt | untitled1.txt | untitled01.txt |

untitled012.txt | untitled012.txt | untitled012.txt | untitled01.txt | untitled1.txt |

untitled1.txt | untitled1.txt | untitled1.txt | untitled2.txt | untitled2.txt |

untitled11.txt | untitled11.txt | untitled11.txt | untitled11.txt | untitled11.txt |

untitled12.psd | untitled12.psd | untitled12.psd | untitled12.psd | untitled12.psd |

untitled2.txt | untitled2.txt | untitled2.txt | untitled012.txt | untitled012.txt |

untitled21.txt | untitled21.txt | untitled21.txt | untitled21.txt | untitled21.txt |

Practical Sign in with Apple: Learn everything you need to know about Sign in with Apple to be able to integrate it in your existing app or a new one.

## Conclusion

So here is the rule of thumbs. When you need to sort or work with text presented to the user, use the `localizedStandardCompare(_:)`

. It compares your strings in a way that makes sense and is expected by users respecting their locale. `localizedStandardCompare(_:)`

will give you the same result as System Finder does. So, using it will give a result that Apple users are already accustomed to.

If you have a particular need that doesn't match what `localizedStandardCompare(_:)`

provided, you can use `compare(_:options:range:locale:)`

. But please make sure you pass the user’s locale as an argument to get a locale-aware feature.

`let custom = files.sorted { (lhs: String, rhs: String) -> Bool in`

let options: String.CompareOptions = [] // customize options

return lhs.compare(rhs, options: options, locale: Locale.current) == .orderedAscending

}

## Related Resources

Apple Documentation

Read more article about Swift, String, Sort, Array, or see all available topic

Feel free to follow me on Twitter and ask your questions related to this post. Thanks for reading and see you next time.

If you enjoy my writing, please check out my Patreon https://www.patreon.com/sarunw and become my supporter. Sharing the article is also greatly appreciated.

Become a patron Tweet ShareHow to specify fractional digits for formatted number string in Swift

Learn how to format a Float and Double string.