Start learning free

LESSON 129 OF 678 · DICTIONARIES

Checking for a Key in a Swift Dictionary

Lesson Read the full explanation

TL ; DR:

A lookup gives nil when the key is missing. So dict[key] != nil asks whether a dictionary has a key.


let capitals: [String: String] = ["France": "Paris", "Japan": "Tokyo"]

if capitals["Japan"] != nil {
    print(capitals["Japan"]!)   // Tokyo
}

if capitals["Spain"] == nil {
    print("No Spain")           // No Spain
}


Full lesson:

You met this in Optionals & Unwrapping. capitals["Spain"] gives nil, and ! on it crashes the program.

capitals["Spain"] != nil is true when "Spain" is a key. == nil asks the opposite.

Inside the first if, the ! is safe. The if just checked the key.

if let does both at once. if let city = capitals["Japan"] checks the key and gives you its value.

A value is not a key

A lookup uses only the keys. capitals["Paris"] is nil, because "Paris" is a value.

A key must match exactly, upper and lower case too. capitals["japan"] is nil.


Your task

In pets, each key is a pet's name, and its value is the pet's kind.

First, check whether "Tom" is a key of pets. If it is, print Tom is a followed by Tom's kind.

Then check that "cat" is not a key, with == nil. If so, print cat is not a key.

"cat" is in pets, but only as a value. It is Tom's kind.

Expected output:

Tom is a cat
cat is not a key
STEP 1 OF 2
    Ctrl + Enter to check

    SWIFT · DICTIONARIES

    Dictionary Key Check in Swift, explained

    A missing key gives nil

    A dictionary lookup in Swift never fails for a key that isn't there. The subscript returns an optional: the value when the key exists, and nil when it doesn't. For a dictionary of type [String: String], a lookup has type String?.

    let capitals: [String: String] = ["France": "Paris", "Japan": "Tokyo"]
    print(type(of: capitals["Spain"]))
    
    Optional<String>
    

    That gives a simple test. capitals["Japan"] != nil is true when "Japan" is a key, and capitals["Spain"] == nil is true when "Spain" is not.

    if capitals["Japan"] != nil {
        print(capitals["Japan"]!)
    }
    if capitals["Spain"] == nil {
        print("No Spain")
    }
    
    Tokyo
    No Spain
    

    Why the ! is safe in one place only

    The ! after a lookup forces the optional open. On a missing key that crashes the program, because there is no value to unwrap. Inside the first if above, the key was just checked, so the ! is safe. Outside such a check, capitals["Spain"]! would stop the program.

    When you want the check and the value together, if let does both:

    if let city = capitals["Japan"] {
        print(city)
    }
    
    Tokyo
    

    The body runs only when the key exists, and city is already a plain String, so no ! is needed.

    Which form to pick

    Use != nil or == nil when you only need a yes or no, as in "is this name taken?". Use if let when you need the value as well. It looks the key up once, and it can never crash, so it is the safer habit. The lesson's exercise uses the != nil form with ! on purpose, to show why the check and the unwrap belong together.

    Checking several keys

    The same test works in a loop. Here each country is looked up with if let, and the else branch handles a missing key:

    for country in ["France", "Spain", "japan"] {
        if let city = capitals[country] {
            print(country + " -> " + city)
        } else {
            print(country + " is not a key")
        }
    }
    
    France -> Paris
    Spain is not a key
    japan is not a key
    

    The third name is not found only because of its lowercase first letter. That is how strict the match is.

    Traps

    • A value is not a key. A lookup uses only the keys. In capitals, the lookup capitals["Paris"] is nil, because "Paris" is a value.
    • Keys must match exactly, letter case included: capitals["japan"] is nil.
    • Don't treat the result as a plain value. let x: String = capitals["Japan"] doesn't compile, because the lookup is optional.

    There is also capitals.keys.contains("France"), which asks the same question about the keys explicitly. The != nil form is the one this lesson uses.

    One more point: a key whose value happens to be an empty string is still a key. ["a": ""]["a"] is Optional(""), not nil, so the check != nil is true. Only a truly absent key gives nil.

    The exercise: pets

    In pets, each key is a pet's name and each value is the pet's kind:

    let pets: [String: String] = ["Rex": "dog", "Tom": "cat", "Polly": "parrot"]
    

    First, check that "Tom" is a key, and print Tom is a followed by his kind. The ! is safe because the if just checked. Then check that "cat" is not a key. It is in pets, but only as a value: it is Tom's kind. The lookup pets["cat"] is nil, so the second message prints.

    let pets: [String: String] = ["Rex": "dog", "Tom": "cat", "Polly": "parrot"]
    if pets["Tom"] != nil {
        print("Tom is a " + pets["Tom"]!)
    }
    if pets["cat"] == nil {
        print("cat is not a key")
    }
    
    Tom is a cat
    cat is not a key
    

    Key takeaways

    • A lookup returns an optional: the value, or nil for a missing key.
    • dict[key] != nil asks whether the key exists, and == nil asks the opposite.
    • Use ! only right after a check, or use if let.
    • Only keys are searched, never values.
    Keep going with Swift500+ step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free