2015-09-10 7 views
2

У меня есть данные, сохраненные таким образом,Применить NSPredicate на [(String, Array, <String>)]

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

Пример данных:

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

Я пытаюсь применить фильтр поиска по этим данным с помощью предиката,

Вот что я пытался и не удалось,

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?

Как и, если условие поиска является «», то data должен фильтровать по

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

Кто просто ответил на мой вопрос, а затем удалил его, пожалуйста, отправить его снова! Я просто попробовал, и он работает, но поиск происходит по первому параметру 'data', но не по второму параметру, который является моим массивом String. Я думаю, мы близки, не могли бы вы объяснить мне код, пожалуйста? – Rao

+0

Я только что редактировал свой ответ, только что опубликовал его сейчас. Это не похоже на элегантное решение, но оно работает –

ответ

3

Поскольку ваш массив содержит кортежи, вместо того, чтобы использовать 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 $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 
} 

Вызов этот метод из:

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

Работает! Спасибо за добавление комментариев! Теперь я просматриваю код, чтобы понять логику. – Rao

+0

@ Rao: Я только что обновил свой ответ, с упрощенной логикой –

+0

Спасибо! Зачем нам нужно 'let arr = arrStr as [String]'? Не могли ли мы использовать 'arrStr'? – Rao

2

Возможное решение с map() и 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])] 

Первый map() отображает каждый кортеж (letter, words)(letter, filteredWords) в соответствии с текстом поиска. Следующие filter() затем удаляет кортежи, для которых filteredWords пуст.

только незначительные изменения, которые необходимы для Swift 2:

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

Это круто! Короткие и эффективные. – Rao