Dictionary.init to Make Use of Swift.Identifiable

In my conceptual post about equality vs identity, I mentioned Helge Heß’ advice to use a Dictionary with an ID as key, and the identified object as value when you would (wrongly) reach for Set and Hashable.

I found a code snippet for this from late last year just for this!

The initializer Dictionary.init(_:uniquingKeysWith:) takes a sequence of (Key, Value) tuples and a closure to resolve duplicate key conflicts.

The following code makes use of the Identifiable protocol to infer the Key to be the ID. The call site becomes:

let foos: [Foo] = ...
let dict: [Foo.ID : Foo] =
    Dictionary(foos, uniquingKeysWith: { _, last in last })

You could also argue for uniquing with { first, _ in first } to discard subsequent objects with the same ID and keep the initial one instead.

And here’s the declaration:

extension Dictionary
where Value: Identifiable, Value.ID == Key {
    @inlinable init<S>(
        _ elements: S,
        uniquingKeysWith combine: (Value, Value) throws -> Value
    ) rethrows where S : Sequence, S.Element == Value {
        try self.init(
            elements.map { ($0.id, $0) },
            uniquingKeysWith: combine)
    }
}