簡體   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