在Swift中使用关键字过滤数组数组

时间:2016-03-15 03:17:56

标签: ios arrays swift filter

let searchResultItem1 = SearchResult()
searchResultItem1.type = "contact"
searchResultItem1.typeTitle = "CONTACTS"
searchResultItem1.results = ["Joe" , "Smith" , "Alan" , "Nick" , "Jason"]

let searchResultItem2 = SearchResult()
searchResultItem2.type = "address"
searchResultItem2.typeTitle = "ADDRESS"
searchResultItem2.results = ["829 6th Street North Fullerton" , "669   Windsor Drive Randallstown" , "423 Front Street Lacey"]
searchResults.append(searchResultItem1)
searchResults.append(searchResultItem2)

当我搜索" al"我希望返回一个SearchResult及其结果" [Alan]"另一个SearchResult及其结果" [" 669 Windsor Drive Randallstown"]"

我尝试了以下过滤器,但返回空数组。

let results = searchResults.filter({$0.results.contains("al")})

3 个答案:

答案 0 :(得分:3)

filter范围内,每个示例中都有$0.results

["Joe" , "Smith" , "Alan" , "Nick" , "Jason"]
["829 6th Street North Fullerton" , "669   Windsor Drive Randallstown" , "423 Front Street Lacey"]

Array.contains(_)函数搜索与其参数完全匹配的对象,而不是参数的子字符串

要使用子字符串" al"获取包含字符串元素的每个整个数组,请使用:

let results = searchResults.filter({$0.results.filter({$0.rangeOfString("al") != nil}).count > 0})

或者,要使用子字符串" al"来获取字符串,请使用:

let results = searchResults.map{ $0.results }.reduce([], combine: {$0 + $1}).filter { $0.rangeOfString("al") != nil }

请注意,这不匹配" Alan"因为rangeOfString区分大小写。

答案 1 :(得分:2)

As both other answers point out, you're searching your array of results for an item with a value of "al". What you're wanting to is actually return an array of results, narrowed down to only those that match:

struct SearchResult {
    let type:String
    let typeTitle:String
    let results:[String]
}

let searchResultItem1 = SearchResult(
    type: "contact",
    typeTitle: "CONTACTS",
    results: ["Joe" , "Smith" , "Alan" , "Nick" , "Jason"]
)

let searchResultItem2 = SearchResult(
    type:"address",
    typeTitle: "ADDRESS",
    results:["829 6th Street North Fullerton" , "669   Windsor Drive Randallstown" , "423 Front Street Lacey"]
)

var searchResults = [ searchResultItem1, searchResultItem2 ]

Now then, again, for convenience, define a case insensitive contains function for String:

extension String {
    func containsIgnoreCase(substring:String) -> Bool {
        return rangeOfString(
            substring,
            options: .CaseInsensitiveSearch,
            range: startIndex..<endIndex,
            locale: nil)?.startIndex != nil
    }
}

Note that String already has a contains function, it's just case sensitive, but if that's sufficient, you don't even need to define your own.

Now, you can use map to get rid of results that don't contain your search string:

searchResults = searchResults.map({
    return SearchResult(
        type: $0.type,
        typeTitle: $0.typeTitle,
        results: $0.results.filter({
            $0.containsIgnoreCase("al")
        })
    )
})

And, presumably, you also want to eliminate any SearchResult with no actual results, so use filter:

searchResults = searchResults.filter { $0.results.count > 0 }

Of course, the whole thing can be strung into one expression:

searchResults = searchResults.map({
    return SearchResult(
        type: $0.type,
        typeTitle: $0.typeTitle,
        results: $0.results.filter({
            $0.contains("al")
        })
    )
}).filter { $0.results.count > 0 }

And, you can possibly further reduce some of the iteration by using flatMap, which is like map, but eliminates any nil values:

searchResults = searchResults.flatMap {
    let results = $0.results.filter { $0.containsIgnoreCase("al") }
    if results.count > 0 {
        return SearchResult(type: $0.type, typeTitle: $0.typeTitle, results: results)
    } else {
        return nil
    }
}

答案 2 :(得分:1)

您的过滤器检查结果数组是否包含&#34; al&#34;的条目,如果结果中的任何字符串包含&#34; al&#34;则不会。您需要过滤结果数组并使用筛选结果数组构造新的SearchResult。

我可能会平面映射一个过滤输入SearchResult的结果数组的函数,并根据是否找到任何匹配返回一个可选项。