Reputation: 69
In my app I built a SearchBar which, for a single word, works perfectly fine.
import Foundation
class Clinic {
var id = ""
var name = ""
var address = ""
var specialty1 = ""
var specialty2 = ""
}
In my textDidChange I have
var clinics: [Clinic] = [] // Clinics Data Structure
var clinicsSearch: [Clinic] = [] // Filtered Clinics
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
// works for one word (either in name or specialty1 or specialty2)
clinicsSearch = clinics.filter { $0.name.lowercased().contains(searchText.lowercased()) ||
$0.specialty1.lowercased().contains(searchText.lowercased()) ||
$0.specialty2.lowercased().contains(searchText.lowercased())
}
searching = true
tableView.reloadData()
}
With the func above, if I start typing something, it will bring all results that meet the criteria (if the typed word is found in the Name OR Specialty1 OR Specialty2).
I now started to look to improve my code and want to implement an option where the user could type words in different order like: Name SPACE specialty(1or2), specialty(1or2) SPACE Name etc and the app would search all 3 fields for all typed words. Order independent.
I found here something very similar to what I'm looking for but I couldn't ask there as I'm below 50 reputation Search for multiple words ignoring the order in Swift
The main difference from the solution presented there is that they use basic a array in the example
let filterArray = ["Big green bubble", "Red bubble", "A bubble in green", "Small green bubble", "This bubble is green"]
That is different from mine, that is based in the Class Clinic above. I tried to adapt their code to my case as below
let textString = searchText.lowercased()
let words = textString.components(separatedBy: " ")
clinicsSearch = clinics.map { $0.name.lowercased() }.filter { string in words.allSatisfy { string.components(separatedBy: " ").contains($0) } }
But I get several errors like Value of type 'Clinic' has no member 'lowercased' or Value of type 'Clinic' has no member 'components' (there are others as well) that I don't know how to fix.
Any help is greatly appreciated.
Thanks
Upvotes: 0
Views: 769
Reputation: 100503
You can try
let searArr = searchText.lowercased().components(separatedBy: " ")
clinicsSearch = clinics.filter { item in
let res = searArr.filter { item.name.lowercased().contains($0) ||
item.specialty1.lowercased().contains($0) ||
item.specialty2.lowercased().contains($0)
}
return !res.isEmpty
}
It could be better to do
let searArr = searchText.lowercased().components(separatedBy: " ")
clinicsSearch = clinics.filter { item in
let lowName = item.name.lowercased()
let lowSp1 = item.specialty1.lowercased()
let lowSp2 = item.specialty2.lowercased()
let res = searArr.filter {
lowName.contains($0) ||
lowSp1.contains($0) ||
lowSp2.contains($0)
}
return !res.isEmpty
}
Upvotes: 2