在Swift中同时搜索两个元素?

时间:2018-09-08 18:11:38

标签: swift uisearchbar

我有一个这样的结构:

struct StructName {
    var name: String?
    var contents: [Content]?

}

Content看起来像这样:

struct Content {
    var contentName: String?
}

现在,我只是按names数组中的StructName搜索

var array = [StructName]()

func searchBar(_ searchBar: UISearchBar, textDidChange searchText:String) {

    var filteredArray = array.filter { $0.name?.range(of: searchText, options: [.caseInsensitive]) != nil}

}

如果我想同时在contents中的name中搜索StructName中的元素,该如何处理?

如果我这样构造它:

let contentA = [Content(contentName: "Content_1"), Content(contentName: "Content_2")]
let contentB = [Content(contentName: "Content_1"), Content(contentName: "Content_2")]
array[0] = (StructName(name: "Name_1", contents: contentA))
array[1] = (StructName(name: "Name_2", contents: contentB))

我在searchText中写了“ NC”,它应该返回所有内容,因为在“ Name_1”和“ Name_2”中有一个“ N”,在“ Content_1”和“ Content_2”中有一个“ C”。

filteredArray的示例:

func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {

        filteredArray = array.filter{ elements in
            var result = false
            elements.contents.forEach{ content in
                if (content.contentName.lowercased().contains(searchText.lowercased()) ) {
                    result = true

                }
            }

            if (content.name?.lowercased().contains(searchText.lowercased()))!{
                result = true
            }

            return result
        }
  }

请注意,这并不能同时进行搜索。

2 个答案:

答案 0 :(得分:1)

如果要过滤和查找StructNames(内容数组项与searchBar文本进行比较),请参见以下代码

struct Content {
    var contentValue: String
}

struct StructName{
    var name: String?
    var contents: [Content]?
}

var array = [ StructName(name: "test1", contents: [ Content(contentValue: "contentValue1"), Content(contentValue: "contentValue2"), Content(contentValue: "searchedText") ]) ]

let searchedText = "searchedText"

let filteredArray = array.filter{ structName in
    var result = false
    structName.contents?.forEach{ content in
        if (content.contentValue.lowercased().contains(searchedText.lowercased()) ) {
            result = true
        }
    }
    return result
}

答案 1 :(得分:1)

您对同时一词的用法不够清楚,无法描述您期望的搜索结果类型。

我认为,

如果(且仅当)name 匹配 searchTextcontentName中的任何contents 匹配 {{ 1}},则searchText实例出现在StructName中。

匹配项的定义类似于您帖子中的filteredArray。)

然后您可以编写如下内容:

name

如果这不是您想要的,则可能需要更精确地指定搜索条件。


(顺便问一下,var filteredArray = array.filter { $0.name?.range(of: searchText, options: .caseInsensitive) != nil || $0.contents?.contains {content in content.contentName?.range(of: searchText, options: .caseInsensitive) != nil} == true } 还是name是可选的吗?)


(对于您的更新示例)

您似乎想按字符进行基于字符的搜索需要

使用一些修改后的示例:

contents

具有一些调试帮助:

var array = [StructName]()
let contentA = [Content(contentName: "Content_1"), Content(contentName: "Content_2")]
let contentB = [Content(contentName: "Content_3"), Content(contentName: "Content_4")]
array.append(StructName(name: "Name_1", contents: contentA))
array.append(StructName(name: "Name_2", contents: contentB))

您可以这样写:

extension StructName: CustomStringConvertible {
    var description: String {
        return "\(name ?? ""):\(contents?.map{$0.contentName ?? ""}.joined(separator: ";") ?? "")"
    }
}
print(array) //->[Name_1:Content_1;Content_2, Name_2:Content_3;Content_4]

输出示例:

func searchBar(_ searchBar: UISearchBar, textDidChange searchText:String) {
    let filteredArray = array.filter {element in
        !searchText.lowercased().contains {searchChar in
            !(element.name ?? "").lowercased().contains(searchChar)
                && !(element.contents ?? []).contains {content in (content.contentName ?? "").lowercased().contains(searchChar)}
        }
    }
    print(filteredArray)
}

不过,由于您的描述还不够清楚,所以我不确定这是否符合您的期望。