Make App Pie

Training for Developers and Artists

The Swift Swift Tutorial: How to Use Dictionaries in Swift

[Updated to Swift 2.0 9/10/2015 SJL]

I wrote early in my Swift tutorials a simple example of a dictionary But I really didn’t go too deep into all the ways one can use a dictionary. In this lesson we’ll bring everyone up to speed in using dictionaries, and for those who don’t know what a dictionary is, we’ll introduce them.

What is a Dictionary

An ordered, indexed array and a unordered dictionary with keys
An ordered, indexed array and a unordered dictionary with keys

Dictionaries and arrays make up the collection types of Swift. Collections are exactly what they say: a collection of values. The difference between an array and a dictionary is how you get the values in and out of the collection. Arrays, as we covered elsewhere, are ordered collections. They have an index which gives their exact place in the collection. I know with an array a value by its position in the array. I know what is before and after my current position by changing the index from its current position.  Arrays must use positive integers in sequence to work this magic.

Dictionaries are unordered collections. No one knows which value comes next, and we really don’t care. The power of a dictionary is we have a key, and the key can pretty much be anything we like that’s a unique value.  One of the most common keys will be strings, but integers and doubles can certainly be used. Dictionaries look up values by the key.

While in an array we pair an index with a value, we pair a key with a value in a dictionary. In Swift, all keys are the same type and all values are the same type in a given dictionary. The value can be of any type, even other objects or collection types. We call the key, then a value returns. Often we find a syntax of key:value for dictionary pairs.

In this lesson for most of these examples, we’ll use a playground. Set up a new playground named SwiftDictionary.

How to Declare a Dictionary

The simplest declaration is to let implicit typing do all the work. We declare a variable or constant and list the key:value pairs in square brackets.

let cookies = ["Chocolate Chip":0.25,"Oatmeal":0.26,"Peanut Butter":0.02,"Sugar":0.03]

This would create an unmutable dictionary. We can refer to it, but can not change any value. For a mutable dictionary, we could use this:

var mutableCookies = ["Macadamia Nut":0.06,"Coconut":0.20, "Macaron":0.55]

To help with readability in a long list of values, you can list them on multiple lines like this:

var gelato = [
       "Coconut":0.25,
       "Pistachio":0.26,
       "Stracciatella":0.02,
       "Chocolate":0.03,
       "Peanut Butter":0.01,
       "Bubble Gum":0.01
]

You can explicitly type your of key:value pairs. The preferred way to do this is:

let piePrice:[String:Double] = [
    "Apple":3.99,"Raspberry":3.35
]

We specify the types in the key value pair surrounded by square brackets. Here we have a string for the key, and a double for the value. There is another  declaration which is available but frowned on by Apple.

let piePrice:Dictionary<string,double> = [
    "Apple":3.99,"Raspberry":0.35
]

This code is identical in function to the previous example but writes out the word Dictionary and uses the <and < characters around the key value pair types.

There are times you need an empty dictionary. In those cases, call the dictionary initializer, which for a dictionary is the key:value pair enclosed in square brackets:

var pieToppings = [String:Double]()

Alternatively, though frowned upon by Apple, you can do this too:

var pizzaSizes = Dictionary<Int, String>()

How to Access a Dictionary

If I wanted to know the price of two slices of pie, the basic syntax is the same for an array, but instead of an index in the square brackets we place the key. We’ve already declared pie prices per slice like this:

let piePrice:[String:Double] = ["Apple":3.99,"Raspberry":0.35]

Like an array’s index, you place the key on brackets:

piePrice["Apple"]

I might write in my code to compute the extend price of pie the following:

let slices = 2.0
let extPrice = piePrice["Apple"]! * slices
println("\(slices) of Apple Pie is \(extPrice)")

The code piePrice["Apple"] returns the price of a slice of apple pie. Notice I wrote piePrice["Apple"]!, with the forced unwrap optional operator. Returned dictionary values are always optionals. At any given time, I do not know if there is a certain type of pie or not in my dictionary. If I tried piePrice["Coconut Cream"] I need some way to tell me that there is no coconut cream pies in my dictionary. Type

piePrice["Coconut Cream"]

The playground returns nil. Swift makes the return value of a dictionary an optional value, so it will return nil if there is no such entry.

If your dictionary is a constant, you know exactly what’s there. In that case, a forced unwrap like above is fine. If you have a dictionary where you may add or delete elements from the dictionary, make sure you check for nil.

if piePrice["Apple"] != nil {
    let extPrice = piePrice["Apple"]! * slices
    print("\(slices) slices of Apple Pie is \(extPrice)")
}

or more compactly with optional chaining

if let price = piePrice["Apple"]{
    let extPrice = price * slices
    print("\(slices) slices of Apple Pie is \(extPrice)")
}

If you are not familiar with optionals, refer to the Ten Points for Using Optionals post to get yourself up to speed.
Of course, keys are not always literal. We can use a variable or constant. We can change the code above to include a constant for the gelato type.:

let gelatoType = "Pistachio"
    if let price = gelato[gelatoType] {
        let extPrice = price * slices
        print("\(slices) scoops of " 
            + gelatoType 
            + " is \(extPrice)")
}

Change a Dictionary

Suppose we have a dictionary of prices for pizza by a unit area like a square inch, square cm or such. Add this dictionary:

var toppings = ["Pepperoni":0.25,
    "Sausage":0.26,
    "Onions":0.02,
    "Green Peppers":0.03,
    "Cheese":0.01
]

Our cost of Sausage and Cheese increases, and we need to change prices in our dictionary. We can change the value with assignment:

toppings["Sausage"] = 0.29
toppings["Sausage"]

Assignment uses subscript syntax and simply changes the value.

toppings.updateValue(0.2, forKey: "Cheese")
toppings["Cheese"]

Line 2 uses the updateValue(value:,forKey:) which does the same as line 1 but the function returns a value. You can write line 2 like this as well:

let oldTopping = toppings.updateValue(0.02,forKey: "Cheese")
if oldTopping == nil{
    print("Key not found")
}

The method returns the value as an optional before we changed it. If there is no key, updateValue(value:,forKey:) returns nil. There is a check to tell the developer that this was not in the dictionary. No value is not a fatal error, unlike an array. If we change a value that isn’t there, such as:

let anotherTopping = toppings.updateValue(0.15,forKey: "Gorgonzola")
toppings["BBQ Chicken"] = 0.24

Swift will add the new entry to the dictionary. There are times that we may not want to add a new element, but give an error or do something else. Using updateValue(value:,forKey:)  we can  check for nil. If nil, we  execute code to delete the new value and do whatever we need to for an unknown key.

To delete a dictionary entry, you can set its value to nil:

gelato["Bubble Gum"] = nil
gelato

You can also use the removeValueForKey method

let deletedTopping = gelato.removeValueForKey("Peanut Butter")
deletedTopping
gelato

The method removeValueforKey(:key) deletes the element. Like updateValue(value:,forKey:) the method returns the value deleted. When deleting an element that does not exist, the method tells you by returning nil, and the subscript syntax does nothing. The rule is simple: If you need to know there was no key present, use the method version.

Iterating Dictionaries

Sometimes we need to list or change everything in a dictionary. You can use the for..in loop to do that. If you need to print a list of all entries and their values in the toppings dictionary, create a tuple with identifier names:

for (myKey,myValue) in toppings {
    print("\(myKey) \t \(myValue)")
}

Here we don’t have optionals involved, since all values are existing values. If we need to iterate through just keys or values we can do that using the .keys or .values. To list all the values , we could do this:

for myValue  in toppings.values{
    print ("Value =  \(myValue)")
}

The iterator myValue here is a constant inside of the loop. You cannot change this value. For example, if we need to make a 10% increase in prices for our toppings we can’t write:

for myValue  in toppings.values{
    myValue = myValue * 1.10
}

The compiler would tell us:

Cannot assign to 'let' value 'myValue'.

We cannot use the values in the for..in loop to do this. If we want to change values in the loop, we iterate over the keys.  Do the calculation directly to the dictionary value based on the iterated key.

//make a 10% price increase
for myKey  in toppings.keys{
    toppings[myKey] = toppings[myKey]! * 1.10
}

Sometimes we need an array of the keys or values, since a particular API requires an array. We can use the .keys or .values to create an array:

var valuesArray = [Double](toppings.values)
let keyArray = [String](toppings.keys)

Passing a Dictionary as a Parameter

Sometimes you will need to pass a lot of values of the same type in a method through a parameter. Instead of making a dozen parameters, you can store their values in a dictionary.

func myFunction(dictionary:[String:Double],key:String)-> Double?{
    return dictionary[key]
}

myFunction(gelato,key: "Coconut")

While this really does nothing special, it make a good prototype function. You can see how to declare a dictionary in a function. Declare the dictionary like you would in an explicit let or var statement. Note here I made the return value Double? to let the optional value through.

Examples Using a Dictionary

Here’s some examples of a dictionary in use.  Let’s look at some code from the PizzaDemo App I created in other lessons. In that earlier post, I stored a price per square inch of pizza as part of a class called Pizza. I can declare a literal dictionary like this in pizza:

var pizzaPricePerInSq = [
    "Cheese": 0.03,
    "Sausage": 0.06,
    "Pepperoni": 0.05, 
    "Veggie": 0.04
]

In the Pizza class I also created a computed property with the array of keys for use with a table view.

var typeList:[String] {
    get{
        return Array(pizzaPricePerInSq.keys)
    }
}

I updated the next example a little bit from the original in PizzaDemo. This demonstrates how to get a value from a dictionary, when you might get a nil value. Here the price goes to zero if not found.

func unitPrice(pizzaType:String) ->Double{
    if let unitPrice = toppings[pizzaType] {
        return unitPrice
    }
    else {
        return 0.0
    }
}

I could of course do this as well with optionals and skip the if..else clause.  We would send back nil instead of 0 and the calling function would deal with an unknown key.

In my  UITableview Post I used all of this to make a table view of pizzas and price per square inch.

 override func tableView(tableView: UITableView?, cellForRowAtIndexPath indexPath: NSIndexPath?) -> UITableViewCell? {
 //note I did not check for nil values. Something has to be really broken for these to be nil.
     let row = indexPath!.row //get the array index from the index path
     let cell = tableView!.dequeueReusableCellWithIdentifier("tableCell", forIndexPath: indexPath) as? UITableViewCell //make the cell
     let myRowKey = pizza.typeList[row] //the dictionary key
     cell.textLabel.text = myRowKey
     let myRowData = pizza.pizzaPricePerInSq[myRowKey] //the dictionary value
     cell.detailTextLabel.text = String(format: "%6.3f",myRowData!)
     return cell
 } 
Screenshot 2014-07-09 09.43.05
UITableview example.

I used the dictionary  starting in the highlighted line 5. Dictionaries are non-ordered, and for an ordered object like a table view, I need something to correspond in an ordered fashion to my table view’s indexPath. I used the computed property typelist, which is an array of keys. This is a good way to get a dictionary ordered when needed. Make an array of keys and iterate over the array pointing to the dictionary. In the highlighted Line 7 I take the key and get the price.

We’ve kept the value’s type to something simple. You can declare a value  as a class instead. In my pizza ordering system, I could have a class describing a pizza order, and use a key to hold the order number. Often people use sequential numbers for the order number. If so, an array might work there. Some systems hide data in the order number, like the date, time or server ID. Hopefully this was a helpful introduction to Dictionaries in Swift.

The Whole Code

Here is a file of the playground for this lesson. While typing in the code above is very useful you can use this to experiment with dictionaries.

//: Playground - noun: a place where people can play

import UIKit

//SwiftDictionary
//(c)2015  Steven Lipton

// declare a unmutable dictionary
let cookies = ["Chocolate Chip":0.25,"Oatmeal":0.26,"Peanut Butter":0.02,"Sugar":0.03]
//declare a mutable dictionary
var mutableCookies = ["Macadamia Nut":0.06,"Coconut":0.20, "Macaron":0.55]
//A better way to format your 
//code for dictionary entries
var gelato = [
    "Coconut":0.25,
    "Pistachio":0.26,
    "Stracciatella":0.02,
    "Chocolate":0.03,
    "Peanut Butter":0.01,
    "Bubble Gum":0.01
]

//Explicit defintion of the key and value
let piePrice:[String:Double] = [
    "Apple":3.99,
    "Raspberry":3.35
]
/* use the one above instead
let piePrice:Dictionary<string,double> = [
    "Apple":3.99,"Raspberry":0.35
]
*/
//Two cases of empty dictionary declarations
var pieToppings = [String:Double]()

var pizzaSizes = Dictionary<Int, String>()

//return a value using a key
piePrice["Apple"]

//Return a value in an expression
//note the reurned value is optional
//so we have to unwrap it
let slices = 2.0
let extPrice = piePrice["Apple"]! * slices
print("\(slices) slices of Apple Pie is \(extPrice)")

//What happens when a key does not exist?
//We get nil
piePrice["Coconut Cream"]

//Check for nil
if piePrice["Apple"] != nil {
    let extPrice = piePrice["Apple"]! * slices
    print("\(slices) slices of Apple Pie is \(extPrice)")
}

//Optional Chaining
if let price = piePrice["Apple"]{
    let extPrice = price * slices
    print("\(slices) slices of Apple Pie is \(extPrice)")
}

//the key as a constant
let gelatoType = "Pistachio"
if let price = gelato[gelatoType] {
    let extPrice = price * slices
    print("\(slices) scoops of " + gelatoType + " is \(extPrice)")
}
//Making a list of toppings, and then changing values
var toppings = ["Pepperoni":0.25,
    "Sausage":0.26,
    "Onions":0.02,
    "Green Peppers":0.03,
    "Cheese":0.01
]
//Change Sausage to 0.29
toppings["Sausage"] = 0.29
toppings["Sausage"]

//Change Cheese to 0.2
toppings.updateValue(0.2, forKey: "Cheese")
toppings["Cheese"]

//Warn an updated value does not exist
let oldTopping = toppings.updateValue(0.02,forKey: "Cheese")
if oldTopping == nil{
    print("Key not found")
}
//Actaully that adds a entry to the dictionary. 
//you can add a entry with the updateValue method too
let anotherTopping = toppings.updateValue(0.15,forKey: "Gorgonzola")
toppings["BBQ Chicken"] = 0.24

//Deleting an entry in the dictionary
//set its value to nil
gelato["Bubble Gum"] = nil
gelato

//Delete a entry using a function
let deletedTopping = gelato.removeValueForKey("Peanut Butter")
deletedTopping //deleted entry
gelato //its gone now

//Loop through values and keys
for (myKey,myValue) in toppings {
    print("\(myKey) \t \(myValue)")
}
//Loop through values
for myValue  in toppings.values{
    print ("Value =  \(myValue)")
}

//make a 10% price increase
//with a loop of keys
for myKey  in toppings.keys{
    toppings[myKey] = toppings[myKey]! * 1.10
}

//getting an array of keys or values
var valuesArray = [Double](toppings.values)
let keyArray = [String](toppings.keys)


// passing dictionaries  through parameters
//very useful if you have to pass a lot of values of they same type as one parameter
func myFunction(dictionary:[String:Double],key:String)-> Double?{
    return dictionary[key]
}
myFunction(gelato,key: "Coconut")


12 responses to “The Swift Swift Tutorial: How to Use Dictionaries in Swift”

  1. Thank You very much for the tutorials I am enjoying reading them However: Having to scroll the code sections back and forth horizontally is quite painful

    1. I’ll see what I can do.

  2. I have been meaning to change this. Thanks for the kick in the pants. Hopefully that should be better.

  3. […] Now we have a price for every pizza, based on size and ingredients. This was a simple and bit contrived example, but it shows how easy using dictionaries are using Swift. For more on Dictionaries, check out my postHow to use Dictionaries in Swift. […]

  4. […] The Swift Swift Tutorial: How to Use Dictionaries in Swift […]

  5. […] Dictionaries:How to use Dictionaries in Swift […]

  6. If I use the same dictionary, how could do to show a UITableView only the dictionary key and when you click on the cell showing me the value of the dictionary in other UIView?

    1. I haven’t updated the code to swift 2.1 yet, but this will give you an example of exactly that:
      https://makeapppie.com/2014/07/05/using-delegates-and-segues-part-2-the-pizza-demo-app/

  7. […] Now we have a price for every pizza, based on size and ingredients. This was a simple and bit contrived example, but it shows how easy using dictionaries are using Swift. For more on Dictionaries, check out my post How to use Dictionaries in Swift. […]

  8. […] The Swift Swift Tutorial: How to Use Dictionaries in Swift | Making App Pie […]

  9. Hello, thank you very much for the detailed tutorial on the dictionary.
    Now I have a little issue, can anyone please help me out. I want to create an if else loop to check whether the key has the value that I want. the values of the key keep changing. so how to do that? is it like this?

    if dict[key] == “value”
    {
    do thing
    }
    else
    {
    do thing
    }
    is this a correct way?

    1. pretty much, yes. However dict[key] is optional, so you might want to check for nil first.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: