GO FURTHER, FASTER: Try the Swift Career Accelerator today! >>

Five useful methods of dictionaries

Filtering, mapping, capacity, and more!

Paul Hudson       @twostraws

Dictionaries are one of Swift’s most commonly used types, so it’s worth taking a few minutes to get to know them a bit better – even discovering one or two new techniques can make a big difference to your projects.

In this article I want to introduce you to five dictionary methods that deserve to be used more. None of them are complicated, so you should be able to read this whole thing in under ten minutes.

Hacking with Swift is sponsored by RevenueCat.

SPONSORED Take the pain out of configuring and testing your paywalls. RevenueCat's Paywalls allow you to remotely configure and A/B test your entire paywall UI without any code changes or app updates.

Learn more here

Sponsor Hacking with Swift and reach the world's largest Swift community!

1. Transforming values

You should already be familiar with the map() method of sequences (if not, see here), but it’s less useful with dictionaries because it’s possible you might create a duplicate dictionary key as part of your transformation.

As a result, dictionaries get a bonus method called mapValues(): this transforms each value inside a dictionary, putting the transformed result into a new dictionary using the original keys. This gives us the transforming behavior of map() without the risk of duplicate keys.

As an example, here’s a dictionary of strings and integers that store results from an exam:

let results = ["Meghan": 80, "Chris": 90, "Charlotte": 95]

If we wanted to format those values into strings, we could use mapValues() like this:

let formattedResults = results.mapValues { "Score: \($0)" }

Once that runs, Meghan’s value will be “Score: 80” rather than just 80.

2. Intelligent merging

If you have two dictionaries of the same type and want to merge them into a single array, you might be tempted to try this:

let first = ["a": 1, "b": 2]
let second = ["c": 3]
let third = first + third

Sadly that doesn’t work, because Swift can’t tell whether it will result in duplicated keys. Instead, you should use the merge() and merging() methods – the former merges one dictionary with another in place, and the latter returns a new dictionary.

These methods are possible because they accept a second parameter: a closure that is able to resolve key clashes. This will be given the existing value and the value that would overwrite it, and you get to choose which one you want.

Here’s an example of creating one dictionary then merging another into it:

var hexColors1 = ["red": "#ff0000", "green": "#00ff00"]
let hexColors2 = ["blue": "#0000ff"]
hexColors1.merge(hexColors2) { (_, second) in second }

Using (_, second) in second as the merge resolution closure means “when trying to write an existing value with a new one, always use the new one.”

3. Grouping sequences

Dictionaries have a marvelous initializer called Dictionary(grouping:), and its job is to convert a sequence into a dictionary based on any grouping you want.

As an example, here’s an array of popular Swift conferences:

let conferences = ["AltConf", "App Builders", "NSSpain"]

We could group that into a dictionary, using the first letter of each conference as the key and the conference names stored as an array:

let alphabetical = Dictionary(grouping: conferences) { $0.first! }

That will make alphabetical equal to ["N": ["NSSpain"], "A": ["AltConf", "App Builders"]].

Alternatively, we could group the conferences based on the length of their names, like this:

let length = Dictionary(grouping: conferences) { $0.count }

That will give length the value [7: ["AltConf", "NSSpain"], 12: ["App Builders"]].

4. Filtering data

Earlier versions of Swift used to make filtering dictionaries return an array of tuples, but this has been cleaned up since Swift 4.0.

Nowadays, filtering dictionaries works like you’d expect: your closure is passed the key and value for each element, and any you return true for is included in a resulting dictionary.

For example, this would filter our exam results dictionary so that it includes only students who scored 85 or over:

let passes = results.filter { key, value in
    return value >= 85
}

5. Reserving capacity

Modifying dictionaries can be costly in Swift, particularly if you modify them repeatedly – you might end up reallocating RAM many times without realizing it.

If you know roughly how many items your dictionary needs – even a vague guess, really – then you should call reserveCapacity() on it before you start adding items. This ensures that your dictionary has contiguous storage allocated for at least the requested number of items so that Swift won’t need to keep reallocating memory.

As an example, if we were asking users to enter in state capitals for the US, we might write code like this:

var stateCapitals = [String: String]()
stateCapitals.reserveCapacity(50)

That reserves enough space for the dictionary to hold 50 items, which will be exactly enough.

Note: This is a minimum amount – you can of course go over, at which point Swift will just reallocate RAM as needed. However, this method is worth using if you even have a vague idea of how much you need.

Hacking with Swift is sponsored by RevenueCat.

SPONSORED Take the pain out of configuring and testing your paywalls. RevenueCat's Paywalls allow you to remotely configure and A/B test your entire paywall UI without any code changes or app updates.

Learn more here

Sponsor Hacking with Swift and reach the world's largest Swift community!

BUY OUR BOOKS
Buy Pro Swift Buy Pro SwiftUI Buy Swift Design Patterns Buy Testing Swift Buy Hacking with iOS Buy Swift Coding Challenges Buy Swift on Sundays Volume One Buy Server-Side Swift Buy Advanced iOS Volume One Buy Advanced iOS Volume Two Buy Advanced iOS Volume Three Buy Hacking with watchOS Buy Hacking with tvOS Buy Hacking with macOS Buy Dive Into SpriteKit Buy Swift in Sixty Seconds Buy Objective-C for Swift Developers Buy Beyond Code

Was this page useful? Let us know!

Average rating: 4.3/5

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.