问题
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