'Check if key exists in dictionary of type [Type:Type?]

How can I check if a key exists in a dictionary? My dictionary is of type [Type:Type?].

I can't simply check dictionary[key] == nil, as that could result from the value being nil.

Any ideas?



Solution 1:[1]

Actually your test dictionary[key] == nil can be used to check if a key exists in a dictionary. It will not yield true if the value is set to nil:

let dict : [String : Int?] = ["a" : 1, "b" : nil]

dict["a"] == nil // false,     dict["a"] is .some(.some(1))
dict["b"] == nil // false !!,  dict["b"] is .some(.none)
dict["c"] == nil // true,      dict["c"] is .none

To distinguish between "key is not present in dict" and "value for key is nil" you can do a nested optional assignment:

if let val = dict["key"] {
    if let x = val {
        print(x)
    } else {
        print("value is nil")
    }
} else {
    print("key is not present in dict")
}

Solution 2:[2]

I believe the Dictionary type's indexForKey(key: Key) is what you're looking for. It returns the index for a given key, but more importantly for your proposes, it returns nil if it can't find the specified key in the dictionary.

if dictionary.indexForKey("someKey") != nil {
    // the key exists in the dictionary
}

Swift 3 syntax....

if dictionary.index(forKey: "someKey") == nil {
    print("the key 'someKey' is NOT in the dictionary")
}

Solution 3:[3]

You can always do:

let arrayOfKeys = dictionary.allKeys
if arrayOfKeys.containsObject(yourKey) {

}
else {
}

However I really dislike the idea of creating an NSDictionary which can contain optionals.

Solution 4:[4]

Try this:

let value = dict[key] != nil

Hope it work for you. Thanks

Solution 5:[5]

As suggested here and above, the best solution is to use Dictionary.index(forKey:) which returns Dictionary<Key, Value>.Index?. Regardless of whether your value is an optional type, this returns an optional index, which if nil, definitively tells you whether the key exists in the dictionary or not. This is much more efficient than using Dictionary.contains(where:) which is documented to have "complexity O(n), where n is the length of the sequence."

So, a much better way to write .containsKey() would be:

extension Dictionary {
  func contains(key: Key) -> Bool {
    self.index(forKey: key) != nil
  }
}

I've been advised that dict.keys.contains() is actually O(1), so feel free to use it if you prefer.

Solution 6:[6]

I handled it this way in Swift 4:

extension Dictionary {
    func contains(key: Key) -> Bool {
        let value = self.contains { (k,_) -> Bool in key == k }
        return value
    }
}

This uses Dictionary.contains(where: (key: Hashable, value: Value) throws -> Bool). By encapsulating it as an extension I have a good shot at updating the implementation to something better without modifying my code. I'm avoiding creating data, which index(forKey:Key) does. I'm hoping it's more efficient than accessing keys since that must create the whole array before searching it.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 vrwim
Solution 3
Solution 4 Sour LeangChhean
Solution 5
Solution 6 Bob Peterson