Reputation: 401
I have an array of Strings in ascending sorted order. I want to filter char/text in that array and get results from searched text letter first and then the rest. I am looking for the simplest way to do this job. Example:
Var array = ["Anand", "Ani", "Dan", "Eion", "Harsh", "Jocab", "Roshan", "Stewart"]
and search text is "R"
Output should be:
Var outArray = ["Roshan", "Harsh", "Stewart"]
Upvotes: 1
Views: 1618
Reputation: 272725
One way to do this is to first map the strings to a tuple containing the index of the search text in string, and the string itself. Then sort by the index, then map the tuples back to the strings.
let array = ["Anand", "Ani", "Dan", "Eion", "Harsh", "Jocab", "Roshan", "Stewart"]
let searchText = "R"
// compactMap acts as a filter, removing the strings where string.index(of: searchText, options: [.caseInsensitive]) returns nil
let result = array.compactMap { string in string.index(of: searchText, options: [.caseInsensitive]).map { ($0, string) } }
.sorted { $0.0 < $1.0 }.map { $0.1 }
The index(of:options:)
method is taken from this answer here.
For Swift 4.x:
extension StringProtocol where Index == String.Index {
func index(of string: Self, options: String.CompareOptions = []) -> Index? {
return range(of: string, options: options)?.lowerBound
}
func endIndex(of string: Self, options: String.CompareOptions = []) -> Index? {
return range(of: string, options: options)?.upperBound
}
func indexes(of string: Self, options: String.CompareOptions = []) -> [Index] {
var result: [Index] = []
var startIndex = self.startIndex
while startIndex < endIndex,
let range = self[startIndex...].range(of: string, options: options) {
result.append(range.lowerBound)
startIndex = range.lowerBound < range.upperBound ? range.upperBound :
index(range.lowerBound, offsetBy: 1, limitedBy: endIndex) ?? endIndex
}
return result
}
func ranges(of string: Self, options: String.CompareOptions = []) -> [Range<Index>] {
var result: [Range<Index>] = []
var startIndex = self.startIndex
while startIndex < endIndex,
let range = self[startIndex...].range(of: string, options: options) {
result.append(range)
startIndex = range.lowerBound < range.upperBound ? range.upperBound :
index(range.lowerBound, offsetBy: 1, limitedBy: endIndex) ?? endIndex
}
return result
}
}
Upvotes: 2
Reputation: 2224
let words = ["Anand", "Ani", "Dan", "Eion", "Harsh", "Jocab", "Roshan", "Stewart"]
let keyword = "r"
let result = words.filter { $0.contains(keyword) }
.sorted { ($0.hasPrefix(keyword) ? 0 : 1) < ($1.hasPrefix(keyword) ? 0 : 1) }
Upvotes: 0
Reputation: 24341
Use filter
on array
to filter all the Strings
that contain the searchText
, i.e.
let array = ["Anand", "Ani", "Dan", "Eion", "Harsh", "Jocab", "Roshan", "Stewart"]
let searchText = "R"
let filteredArray = array.filter({$0.lowercased().contains(searchText.lowercased())})
let sortedArray = filteredArray.sorted { (str1, str2) -> Bool in
if let index1 = str1.lowercased().firstIndex(of: Character(searchText.lowercased())), let index2 = str2.lowercased().firstIndex(of: Character(searchText.lowercased())) {
return index1 < index2
}
return false
}
print(sortedArray) //["Roshan", "Harsh", "Stewart"]
Upvotes: 1