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)
}
}