How do I “append” to an immutable dictionary in Swift?

南楼画角 提交于 2019-12-03 11:59:46

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 (i.e. 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.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!