Sorting a String array and ignoring case
You can convert the String
to lowercase and then compare it:
array.sort{ $0.lowercaseString < $1.lowercaseString }
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))
This is the method that should be used and is intended for this purpose:
public func caseInsensitiveCompare(aString: String) -> NSComparisonResult
In your case:
resultListArray.sort({ $0.fileName.caseInsensitiveCompare($1.fileName) == NSComparisonResult.OrderedAscending })