In Scala, the + (k -> v)
operator on immutable.Map
returns a new immutable.Map
with the contents of the original, plus the new key/value pair. Similarly, in C#, ImmutableDictionary.add(k, v)
returns a new, updated ImmutableDictionary
.
In Swift, however, Dictionary
appears only to have the mutating updateValue(v, forKey: k)
function and the mutating [k:v]
operator.
I thought maybe I could play some trick with flatten()
, but no luck:
let updated = [original, [newKey: newValue]].flatten()
gets me
Cannot convert value of type '() -> FlattenCollection<[[String : AnyObject]]>'
to specified type '[String : AnyObject]'
How do I create a new, modified immutable Dictionary
from the contents of an existing one?
Update: Based on this answer 's note that Swift dictionaries are value types, and this answer 's mutable version, I came up with the following extension operator, but I'm not excited about it -- it seems like there must be a cleaner out-of-the-box alternative.
func + <K, V>(left: [K:V], right: [K:V]) -> [K:V] {
var union = left
for (k, v) in right {
union[k] = v
}
return union
}
But maybe the fact (if I understand correctly) that the immutability of Swift dictionaries is a compiler check on let
rather than a matter of different implementation classes means this is the best that can be done?
Update #2: As noted in Jules's answer , modifying immutable dictionaries that aren't specifically optimized to share state between copies (as Swift dictionaries aren't) presents performance problems. For my current use case ( AttributedString
attribute dictionaries, which tend to be fairly small) it may still simplify certain things enough to be worth doing, but until and unless Swift implements a shared-state immutable dictionary it's probably not a good idea in the general case -- which is a good reason not to have it as a built-in feature.
Unfortunately, this is a good question because the answer is "you can't". Not yet, anyway--others agree this should be added, because there's a Swift Evolution proposal for this (and some other missing Dictionary
features) . It's currently "awaiting review", so you may see a merged()
method that's basically your +
operator in a future version of Swift!
In the meantime, you can use your solution to append entire dictionaries, or for one value at a time:
extension Dictionary {
func appending(_ key: Key, _ value: Value) -> [Key: Value] {
var result = self
result[key] = value
return result
}
}
There's no built-in way to do this right now. You could write your own using an extension (below).
But keep in mind that this will likely copy the dictionary, because dictionaries are copy-on-write, and you're doing exactly that (making a copy, then mutating it). You can avoid all this by just using a mutable variable in the first place :-)
extension Dictionary {
func updatingValue(_ value: Value, forKey key: Key) -> [Key: Value] {
var result = self
result[key] = value
return result
}
}
let d1 = ["a": 1, "b": 2]
d1 // prints ["b": 2, "a": 1]
let d2 = d1.updatingValue(3, forKey: "c")
d1 // still prints ["b": 2, "a": 1]
d2 // prints ["b": 2, "a": 1, "c": 3]
The most straightforward thing to do is to copy to a variable, modify, then re-assign back to a constant:
var updatable = original
updatable[newKey] = newValue
let updated = updatable
Not pretty, obviously, but it could be wrapped into a function easily enough.
extension Dictionary {
func addingValue(_ value: Value, forKey key: Key) -> Dictionary<Key, Value> {
// Could add a guard here to enforce add not update, if needed
var updatable = self
updatable[key] = value
return updatable
}
}
let original = [1 : "One"]
let updated = original.addingValue("Two", forKey: 2)
I don't believe there's a solution other than roll-your-own.
But maybe the fact (if I understand correctly) that the immutability of Swift dictionaries is a compiler check on
let
Right, mutability is specified on the storage , that is, the variable, not on the value .
Do not try to update an immutable dictionary unless it has been specifically designed for immutability.
Immutable dictionaries usually use a data structure (such as a red/black tree with immutable nodes than can be shared between instances or similar) that can generate a modified copy without needing to make copies of the entire content, but only a subset (ie they have O(log(n)) copy-and-modify operations) but most dictionaries that are designed for a mutable system and then used with an immutable interface do not, so have O(n) copy-and-modify operations. When your dictionary starts to get larger than a few hundred nodes, you'll really notice the performance difference.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.