Basically this is a struct object holding a country and its ports
struct countryAndPorts {
var country: String?
var ports: [String]?
}
These are the arrays holding each country mapped to its ports. The filtered array should hold filtered results either by country or ports.
var countryAndPortsArray = [countryAndPorts]()
var filteredArray = [countryAndPorts]()
Currently the function below successfully produces a filtered result using countries as search key
func filteredContent(searchKey: String) {
filteredArray = countryAndPortsArray.flatMap{ $0 }.filter{$0.country?.lowercased().range(of: searchKey) != nil }
}
Now my problem is I wish to get a filtered result either by using a port or country as search key. I have tried my possible best but can't seem to get desirable results using ports as the search key. Improvements on my current method would be much appreciated. Answers in Objective-C are welcomed as well.
//Just incase it's of any use, these are my UITableView delegates
extension SearchDealsViewController: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if let count = filteredArray[section].ports?.count {
return count
}
return 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
if let port = filteredArray[indexPath.section].ports?[indexPath.row] {
cell.textLabel?.text = port
}
cell.textLabel?.font = UIFont.systemFont(ofSize: 10)
return cell
}
func numberOfSections(in tableView: UITableView) -> Int {
return filteredArray.count
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
portsFromTextField.text = filteredArray[indexPath.section].ports?[indexPath.row]
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let header = tableView.dequeueReusableCell(withIdentifier: "header")
let tapSectionHeaderGesture = UITapGestureRecognizer(target: self, action: #selector(getCountryText(sender:)))
tapSectionHeaderGesture.numberOfTouchesRequired = 1
tapSectionHeaderGesture.numberOfTapsRequired = 1
header?.addGestureRecognizer(tapSectionHeaderGesture)
if header != nil {
header?.textLabel?.textColor = THEME_COLOUR
header?.textLabel?.font = UIFont.boldSystemFont(ofSize: 12)
header?.textLabel?.text = filteredArray[section].country
}
return header
}
func getCountryText(sender: UITapGestureRecognizer) {
if let country = sender.view as? UITableViewCell {
portsFromTextField.text = country.textLabel?.text
}
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 30
}
-------------------------------- UDPATE -------------------------------
At the moment typing "vlone" as a search string returns both "vlone" and "vlore". Vlone and Vlore are both ports in Albania
Result yielded using vlone as search string
However the desired output should only include "vlone" and leave out every other port in Albania because the user was specific with their query.
2nd scenario would be using "barcelona" as search key. It returns a result containing every port in Spain however the desired output should only contain Barcelona.
If you want to filter the array to find any entry that has a matching country or port, then you can do:
func filteredContent(searchKey: String) {
filteredArray = countryAndPortsArray.filter {
$0.country?.lowercased().range(of: searchKey) != nil ||
!($0.ports?.filter {
$0.lowercased().range(of: searchKey) != nil
}.isEmpty ?? true)
}
}
Let's break this down. At the top level is the call to filter
on the countryAndPortsArray
array. The filter consists of two parts. 1) checking to see if the country contains the search text, and 2) checking to see if any of the ports contain the search text.
The first check is done with:
$0.country?.lowercased().range(of: searchKey) != nil
which is the part you already had.
The second check is done with:
!($0.ports?.filter {
$0.lowercased().range(of: searchKey) != nil
}.isEmpty ?? true)
Since ports
is an array, a filter is being used to see if any of the ports contains the search text. The isEmpty
is checking if the resulting filter list of matching ports is empty. Since ports
is optional, the use of ?? true
?? true
means to act as if the list of matching ports is empty. The !
negates the results. So if the matching list is empty (or ports
is nil
), the true
is negated to false
indicating that there are no matching ports.
The two checks are combined using the standard logical "or" operator ||
meaning only one of the two checks needs to be true for the top level filter to match that record.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.