如何过滤包含字符串和数组的结构?

时间:2017-04-21 00:17:26

标签: ios arrays swift uitableview data-manipulation

基本上这是一个包含国家及其端口的结构对象

struct countryAndPorts {
   var country: String?
   var ports: [String]?
}

这些是将每个国家/地区映射到其端口的阵列。过滤后的数组应按国家/地区或端口保存过滤结果。

var countryAndPortsArray = [countryAndPorts]()
var filteredArray = [countryAndPorts]()

目前,以下功能使用国家/地区作为搜索键

成功生成过滤结果
func filteredContent(searchKey: String) {
    filteredArray = countryAndPortsArray.flatMap{ $0 }.filter{$0.country?.lowercased().range(of: searchKey) != nil }
}

现在我的问题是我希望通过使用端口或国家/地区作为搜索关键字来获得过滤结果。我已经尽力了,但似乎无法使用端口作为搜索键获得理想的结果。我当前的方法的改进将非常感激。 Objective-C中的答案也受到欢迎。

//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 ----------- --------------------

此时输入“vlone”作为搜索字符串会同时返回“vlone”和“vlore”。 Vlone和Vlore都是阿尔巴尼亚的港口

Result yielded using vlone as search string

但是,所需的输出应仅包含“vlone”,并且不在阿尔巴尼亚的其他所有端口,因为用户特定于他们的查询。

第二种情况是使用“barcelona”作为搜索关键字。它返回包含西班牙每个端口的结果,但是所需的输出应该只包含Barcelona。

Results using barcelona as search key

1 个答案:

答案 0 :(得分:0)

如果要过滤数组以查找具有匹配国家/地区或端口的任何条目,则可以执行以下操作:

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)
    }
}

让我们打破这个局面。在顶层是filter数组上countryAndPortsArray的调用。过滤器由两部分组成。 1)检查国家是否包含搜索文本,以及2)检查是否有任何端口包含搜索文本。

第一次检查完成:

$0.country?.lowercased().range(of: searchKey) != nil

这是你已经拥有的部分。

第二次检查完成:

!($0.ports?.filter {
    $0.lowercased().range(of: searchKey) != nil
}.isEmpty ?? true)

由于ports是一个数组,因此使用过滤器来查看是否有任何端口包含搜索文本。 isEmpty正在检查匹配端口的结果筛选器列表是否为空。由于ports是可选的,因此?? true的使用意味着就像匹配端口列表为空一样。 !否定了结果。因此,如果匹配列表为空(或portsnil),则true将被否定为false,表示没有匹配的端口。

使用标准逻辑"或"组合两个检查。 operator ||表示只有两个检查中的一个必须为顶级过滤器才能匹配该记录。