繁体   English   中英

如何在Swift中“追加”到不可变字典?

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

在Scala中, immutable.Map上的+ (k -> v)运算符返回一个新的immutable.Map ,其中包含原始内容以及新的键/值对。 类似地,在C#中, ImmutableDictionary.add(k, v)返回一个新的,更新的ImmutableDictionary

然而,在Swift中, Dictionary似乎只有变异的updateValue(v, forKey: k)函数和变异的[k:v]运算符。

我想也许我可以用flatten()玩一些技巧,但没有运气:

let updated = [original, [newKey: newValue]].flatten()

抓住我

Cannot convert value of type '() -> FlattenCollection<[[String : AnyObject]]>' 
to specified type '[String : AnyObject]'

如何从现有内容的内容创建新的,修改过的不可变Dictionary


更新:根据这个答案的说明,Swift字典是值类型, 这个答案的可变版本,我想出了以下扩展运算符,但我对此并不感兴趣 - 似乎必须有一个更清洁的开箱即用的替代方案。

func + <K, V>(left: [K:V], right: [K:V]) -> [K:V] {
    var union = left
    for (k, v) in right {
        union[k] = v
    }
    return union
} 

但也许事实(如果我理解正确的话)Swift词典的不变性是编译器检查let而不是不同的实现类的问题意味着这是最好的可以做到的?


更新#2:正如Jules的回答所述 ,修改未经特别优化以在副本之间共享状态的不可变字典(如Swift字典不是)会出现性能问题。 对于我当前的用例( AttributedString属性字典,它往往相当小),它仍然可以简化某些事情,值得做,但除非Swift实现共享状态不可变字典,否则它可能不是一个好主意。 case - 这是不将它作为内置功能的一个很好的理由。

不幸的是,这是一个很好的问题,因为答案是“你不能”。 还没有,无论如何 - 其他人同意这应该添加,因为有一个Swift Evolution提议(以及其他一些缺少的Dictionary功能) 它目前正在“等待审核”,因此您可能会看到一个merged()方法,它基本上是未来Swift版本中的+运算符!

在此期间,您可以使用您的解决方案附加整个词典,或一次添加一个值:

extension Dictionary {
    func appending(_ key: Key, _ value: Value) -> [Key: Value] {
        var result = self
        result[key] = value
        return result
    }
}

现在没有内置的方法可以做到这一点。 你可以使用扩展名编写自己的(下面)。

但请记住,这可能会复制字典,因为字典是写时复制的,而你正是这样做的(制作副本,然后改变它)。 你可以通过首先使用一个可变变量来避免这一切:-)

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]

最直接的事情是复制到变量,修改,然后重新分配回常量:

var updatable = original
updatable[newKey] = newValue
let updated = updatable

显然不是很漂亮,但它可以很容易地包装到一个函数中。

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)

我不相信除了滚动你自己之外还有其他解决方案。

但也许事实(如果我理解正确的话)Swift词典的不变性是对let的编译器检查

是的,可变性是在存储上指定的,即变量,而不是

不要尝试更新不可变字典,除非它是专为不变性而设计的。

不可变字典通常使用数据结构(例如红色/黑色树,其中不可变节点,可以在实例之间共享或类似),可以生成修改后的副本,而无需复制整个内容,但只需要一个子集(即有O(log(n))复制和修改操作)但是大多数为可变系统设计然后与不可变接口一起使用的字典都没有,所以有O(n)复制和修改操作。 当你的字典开始变得超过几百个节点时,你会真正注意到性能差异。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM