The code below works for sorting an array of strings if they are all lowercase or all uppercase but I want to ignore case when I sort. How could I do this? The following is an array of a custom class.
resultListArray.sort({ $0.fileName.compare($1.fileName) == NSComparisonResult.OrderedAscending })
localeCompare() enables case-insensitive sorting for an array.
Sorting on the basis of the ASCII values differentiates the uppercase letters from the lowercase letters, and results in a case-sensitive order. Although the results in the Ascending order column might at first appear somewhat unpredictable, they are not.
To sort an array of strings in Java, we can use Arrays. sort() function.
You can use String method localizedCompare()
update: Xcode 11.5 • Swift 5.2
let array = ["def","Ghi","Abc" ]
let sorted1 = array.sorted{$0.compare($1) == .orderedAscending}
print(sorted1) // ["Abc", "Ghi", "def"] this is case SENSITIVE!
let sorted2 = array.sorted{$0.localizedCompare($1) == .orderedAscending}
print(sorted2) // ["Abc", "def", "Ghi"]
// you can also use the String compare options parameter to give you more control when comparing your strings
let sorted3 = array.sorted{$0.compare($1, options: .caseInsensitive) == .orderedAscending }
print(sorted3) // ["Abc", "def", "Ghi"]\n"
// which can be simplifyed using the string method caseInsensitiveCompare
let sorted4 = array.sorted{$0.caseInsensitiveCompare($1) == .orderedAscending}
print(sorted4) // ["Abc", "def", "Ghi"]\n"
// or localizedStandardCompare (case and diacritic insensitive)
// This method should be used whenever file names or other strings are presented in lists and tables where Finder-like sorting is appropriate. The exact sorting behavior of this method is different under different locales and may be changed in future releases. This method uses the current locale.
let array5 = ["Cafe B","Café C","Café A"]
let sorted5 = array5.sorted { $0.localizedStandardCompare($1) == .orderedAscending }
print(sorted5) // "["Café A", "Cafe B", "Café C"]\n"
You can also implement your own custom sort/sorted methods:
extension Collection where Element: StringProtocol {
public func localizedSorted(_ result: ComparisonResult) -> [Element] {
sorted { $0.localizedCompare($1) == result }
}
public func caseInsensitiveSorted(_ result: ComparisonResult) -> [Element] {
sorted { $0.caseInsensitiveCompare($1) == result }
}
public func localizedCaseInsensitiveSorted(_ result: ComparisonResult) -> [Element] {
sorted { $0.localizedCaseInsensitiveCompare($1) == result }
}
/// This method should be used whenever file names or other strings are presented in lists and tables where Finder-like sorting is appropriate. The exact sorting behavior of this method is different under different locales and may be changed in future releases. This method uses the current locale.
public func localizedStandardSorted(_ result: ComparisonResult) -> [Element] {
sorted { $0.localizedStandardCompare($1) == result }
}
}
extension MutableCollection where Element: StringProtocol, Self: RandomAccessCollection {
public mutating func localizedSort(_ result: ComparisonResult) {
sort { $0.localizedCompare($1) == result }
}
public mutating func caseInsensitiveSort(_ result: ComparisonResult) {
sort { $0.caseInsensitiveCompare($1) == result }
}
public mutating func localizedCaseInsensitiveSort(_ result: ComparisonResult) {
sort { $0.localizedCaseInsensitiveCompare($1) == result }
}
/// This method should be used whenever file names or other strings are presented in lists and tables where Finder-like sorting is appropriate. The exact sorting behavior of this method is different under different locales and may be changed in future releases. This method uses the current locale.
public mutating func localizedStandardSort(_ result: ComparisonResult) {
sort { $0.localizedStandardCompare($1) == result }
}
}
Usage:
var array = ["def","Ghi","Abc" ]
array.caseInsensitiveSort(.orderedAscending)
array // ["Abc", "def", "Ghi"]
To sort a custom object by a string property we can pass a predicate to get the string from the element and use a keypath when calling this method:
extension Collection {
/// This method should be used whenever file names or other strings are presented in lists and tables where Finder-like sorting is appropriate. The exact sorting behavior of this method is different under different locales and may be changed in future releases. This method uses the current locale.
public func localizedStandardSorted<T: StringProtocol>(by predicate: (Element) -> T, ascending: Bool = true) -> [Element] {
sorted { predicate($0).localizedStandardCompare(predicate($1)) == (ascending ? .orderedAscending : .orderedDescending) }
}
}
extension MutableCollection where Self: RandomAccessCollection {
/// This method should be used whenever file names or other strings are presented in lists and tables where Finder-like sorting is appropriate. The exact sorting behavior of this method is different under different locales and may be changed in future releases. This method uses the current locale.
public mutating func localizedStandardSort<T: StringProtocol>(by predicate: (Element) -> T, ascending: Bool = true) {
sort { predicate($0).localizedStandardCompare(predicate($1)) == (ascending ? .orderedAscending : .orderedDescending) }
}
}
Usage:
struct File {
let id: Int
let fileName: String
}
var files: [File] = [.init(id: 2, fileName: "Steve"),
.init(id: 5, fileName: "Bruce"),
.init(id: 3, fileName: "alan")]
let sorted = files.localizedStandardSorted(by: \.fileName)
print(sorted) // [File(id: 3, fileName: "alan"), File(id: 5, fileName: "Bruce"), File(id: 2, fileName: "Steve")]
files.localizedStandardSort(by: \.fileName)
print(files) // [File(id: 3, fileName: "alan"), File(id: 5, fileName: "Bruce"), File(id: 2, fileName: "Steve")]
edit/update:
iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0 or later
You can use the new generic structure KeypathComparator
let sorted = files.sorted(using: KeyPathComparator(\.fileName, comparator: .localizedStandard))
print(sorted) // [File(id: 3, fileName: "alan"), File(id: 5, fileName: "Bruce"), File(id: 2, fileName: "Steve")]
let reversed = files.sorted(using: KeyPathComparator(\.fileName, comparator: .localizedStandard, order: .reverse))
print(reversed) // [File(id: 2, fileName: "Steve"), File(id: 5, fileName: "Bruce"), File(id: 3, fileName: "alan")]
files.sort(using: KeyPathComparator(\.fileName, comparator: .localizedStandard))
print(files) // [File(id: 3, fileName: "alan"), File(id: 5, fileName: "Bruce"), File(id: 2, fileName: "Steve")]
For simple types you need to use self as the KeyPath
var array = ["def","Ghi","Abc"]
let sorted = array.sorted(using: KeyPathComparator(\.self, comparator: .localizedStandard))
Or mutating the original
array.sort(using: KeyPathComparator(\.self, comparator: .localizedStandard))
You can convert the String
to lowercase and then compare it:
array.sort{ $0.lowercaseString < $1.lowercaseString }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With