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

▼魔方 西西 提交于 2019-12-02 06:20:57

问题


I have data stored in this fashion,

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

Example Data:

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

I am trying to apply a search filter on this data by using Predicate,

Here is what I am tried and failed,

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

Its failing as I am trying to convert my data into NSArray to apply filter and then trying to convert the filtered array back to my desired format. (I know that this conversion won't work, this is just to give you guys an idea of what I am trying to do.)

My question is how to apply search filter on my data's array of Strings ?

As in, if the search term is "an", the data should filter to

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

回答1:


Since your array contains tuples, instead of using NSPredicate, you can use the following method for filtering your data:

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 $0.lowercaseString.rangeOfString(ltrToCompare.lowercaseString) != nil
        }

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

Call that method from:

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



回答2:


A possible solution with map() and filter() (Swift 1.2):

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

let filtered = map(data) {
    ($0, $1.filter {
        $0.rangeOfString(searchText, options: .CaseInsensitiveSearch) != nil
    })
}.filter { !isEmpty($1) }

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

The first map() maps each (letter, words) tuple to (letter, filteredWords) according to the search text. The following filter() then removes the tuples for which filteredWords is empty.

Only minor changes are necessary for Swift 2:

let filtered = data.map {
    ($0, $1.filter {
        $0.rangeOfString(searchText, options: .CaseInsensitiveSearch) != nil
    })
}.filter { !$1.isEmpty }


来源:https://stackoverflow.com/questions/32504186/apply-nspredicate-on-string-arraystring

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!