Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift filter for multiple dictionary keys

Tags:

ios

swift

filter

I'm making a search bar for my app. I'm using the filter method to get the results. I want to search through multiple keys.

Array of dictionaries:

var people = [
               ["First": "John", "Last": "Doe"],
               ["First": "Steve", "Last": "Jobs"],
               ["First": "Elon", "Last": "Musk"]
             ]

I am only able to search for either "First" or "Last", but not both, with this code:

searchResults = people.filter{
            var string = $0["Last"] 
            // or "First"

            string = string?.lowercaseString

            return string!.rangeOfString(searchText.lowercaseString) != nil
        }
like image 979
Jeremy Lin Avatar asked Nov 19 '15 00:11

Jeremy Lin


2 Answers

One approach would be to simply compare both fields to the search string:

var people = [
    ["First": "JohnMusk", "Last": "Doe"],
    ["First": "Steve", "Last": "Jobs"],
    ["First": "Elon", "Last": "Musk"]
]

var searchText = "Musk"

var searchResults = people.filter{
        var firstName = $0["First"]!.lowercaseString
        var lastName = $0["Last"]!.lowercaseString

       return firstName.rangeOfString(searchText.lowercaseString) != nil
              || lastName.rangeOfString(searchText.lowercaseString) != nil

}

This gives me this result:

2015-11-18 18:19:47.691 MyPlayground[36558:7031733] (
        {
        First = JohnMusk;
        Last = Doe;
    },
        {
        First = Elon;
        Last = Musk;
    }
)

Which I believe is what you want.

like image 60
Undo Avatar answered Oct 18 '22 07:10

Undo


Here's an alternate approach using NSPredicate. NSPredicate has a very powerful syntax which can do some pretty nice things for you.

let firstNameQuery = "jo"
let lastNameQuery = "mus"
// [cd] means case/diacritic insensitive. %K is used to pass in key names since FIRST and LAST are reserved keywords in NSPredicate
let predicate = NSPredicate(format: "%K CONTAINS[cd] %@ OR %K CONTAINS[cd] %@", "First", firstNameQuery, "Last", lastNameQuery)
let sorted = people.filter({
    return predicate.evaluateWithObject($0)
})
// sorted would contain John Doe and Elon Musk entries

In my example I passed in different search queries for the first and last name, but you could obviously pass in the same query for both. Just demonstrates the power of this approach.

like image 5
Andrew Avatar answered Oct 18 '22 07:10

Andrew