Peter Ruppert
Peter Ruppert

Reputation: 1177

How do I filter NSDictionary with UISearchBar?

I need to change my search function from filtering an array:

func filterContentForSearchText(searchText: String, scope: String = "All") {
    if searchText != "" {

        filteredName = CGCoins.shared.ids.filter {name in
            return   name.lowercased().contains(searchText.lowercased())}
    } else { filteredName = CGCoins.shared.ids

    }
}

to filtering a Dictionary, which contains Symbols and their corresponding names. Ideally, I want to be able to search both the key and the value, for example, the dictionary, (CGCoins.shared.coinDictionary) looks like this:

["btc":"bitcoin","eth":"ethereum","ltc":"litecoin"...]

so I want to be able to search using UISearchBar and be able to search both "btc" and return "bitcoin" or search "bitcoin" and also return "bitcoin".

I have tried this:

func filterNewForSearchText(searchText: String, scope: String = "All") {
    if searchText != "" {

        filteredName = CGCoins.shared.coinDictionary.filter {name in
            return   name.key == searchText}
    } else { filteredName = CGCoins.shared.coinDictionary.values

    }
}

but I get the error:

Cannot assign value of type '[String : String]' to type '[String]'

How can I successfully filter the Dictionary, for both the key and value, and return the Value of whatever is searched? Any alternative solutions are also welcome.

Upvotes: 0

Views: 534

Answers (3)

Leo Dabus
Leo Dabus

Reputation: 236340

Filtering a dictionary returns a tuple you need to map the result and return the dictionary values. In the else part you need to create a new array from its values:

func filterNewForSearchText(searchText: String, scope: String = "All") {
    if !searchText.isEmpty  {
        filteredName = CGCoins.shared.coinDictionary
                           .filter { 
                               $0.key == searchText 

                            // if you need to search key and value and include partial matches
                            // $0.key.contains(searchText) || $0.value.contains(searchText)

                            // if you need to search caseInsensitively key and value and include partial matches
                            // $0.key.range(of: searchText, options: .caseInsensitive) != nil || $0.value.range(of: searchText, options: .caseInsensitive) != nil
                            }
                           .map{ $0.value }
    } else {
        filteredName = Array(CGCoins.shared.coinDictionary.values)
    }
}

Upvotes: 5

ielyamani
ielyamani

Reputation: 18581

The error message comes from the fact that filtering a Dictionary won't return its values automatically, but you'll have to get its keys and then wrap them in an Array:

The following looks for an exact match in the keys, or if the searchText is contained in values:

if searchText != "" {
    filteredName = Array(CGCoins.shared.coinDictionary.filter {name in
        return name.key == searchText || name.value.lowercased().contains(searchText.lowercased())
        }.values)
} else {
    filteredName = Array(CGCoins.shared.coinDictionary.values)
}

Upvotes: 0

Nikunj Kumbhani
Nikunj Kumbhani

Reputation: 3924

Try this one it's Working

For Like Query ( String contains another string )

let data = ["btc":"bitcoin","eth":"ethereum","ltc":"litecoin"]

let filtered = data.filter { $0.key.contains("c") || $0.value.contains("c") }
print(filtered) // ["btc":"bitcoin","ltc":"litecoin"]

For exact matching string

let filtered = data.filter { $0.key == "btc"  || $0.value == "litecoin" }

Upvotes: 0

Related Questions