在 [(String, Array<String>)] 上应用 NSPredicate

Apply NSPredicate on [(String, Array<String>)]

我有以这种方式存储的数据,

var data = [(String, Array<String>)]()

示例数据:

[(A, [Apple, Andy, Android]), (B, [Banana, Breakfast])]

我正在尝试使用 Predicate 对此数据应用搜索过滤器,

这是我尝试过但失败了的方法,

func updateSearchResultsForSearchController(searchController: UISearchController) {
      let searchPredicate = NSPredicate(format: "SELF CONTAINS[c] %@", searchController.searchBar.text) 
      let array = (data as NSArray).filteredArrayUsingPredicate(searchPredicate)
      data = array as! [(String, Array<String>)]

      //reload tableView with fresh data
      self.tableView.reloadData()
}

它失败了,因为我试图将我的 data 转换为 NSArray 以应用过滤器,然后尝试将过滤后的数组转换回我想要的格式。 (我知道这种转换是行不通的,这只是为了让你们了解我正在尝试做的事情。)

我的问题是如何对 data 的字符串数组应用搜索过滤器?

例如,如果搜索词是 "an",data 应该过滤到

[(A, [Andy, Android]), (B, [Banana])]

由于您的数组包含元组,而不是使用 NSPredicate,您可以使用以下方法过滤数据:

func getFilteredData(data : [(String, Array<String>)], ltrToCompare : String) -> [(String, Array<String>)]
{
    // For keeping the filtered result
    var returnData = [(String, Array<String>)]()

    // Looping through parent array        
    for (letter, arr) in data
    {
        // Filters the internal array [String]
        let filter = arr.filter()
        {
            return [=10=].lowercaseString.rangeOfString(ltrToCompare.lowercaseString) != nil
        }

        // Checks whether the inner array filtering returns any element
        if (filter.count != 0)
        {
            returnData.append((letter, filter));
        }
    }
    return returnData
}

从以下位置调用该方法:

func updateSearchResultsForSearchController(searchController: UISearchController)
{
      data = getFilteredData(data, ltrToCompare: searchController.searchBar.text)
      //reload tableView with fresh data
      self.tableView.reloadData()
}

map()filter() (Swift 1.2) 的可能解决方案:

let data = [("A", ["Apple", "Andy", "Android"]), ("B", ["Banana", "Breakfast"])]
let searchText = "an"

let filtered = map(data) {
    ([=10=], .filter {
        [=10=].rangeOfString(searchText, options: .CaseInsensitiveSearch) != nil
    })
}.filter { !isEmpty() }

println(filtered)
// [(A, [Andy, Android]), (B, [Banana])]

第一个 map() 根据搜索文本将每个 (letter, words) 元组映射到 (letter, filteredWords)。 随后的 filter() 然后删除 filteredWords 为空的元组。

Swift 2:

只需要稍作改动
let filtered = data.map {
    ([=11=], .filter {
        [=11=].rangeOfString(searchText, options: .CaseInsensitiveSearch) != nil
    })
}.filter { !.isEmpty }