【问题标题】:How to combine two Dictionary instances in Swift?如何在 Swift 中组合两个 Dictionary 实例?
【发布时间】:2014-12-30 22:47:21
【问题描述】:

如何使用Swift 将一个Dictionary 附加到另一个Dictionary

我正在使用AlamoFire 库将JSON 发送到REST server

字典 1

var dict1: [String: AnyObject] = [
    kFacebook: [
        kToken: token
    ]
]

字典 2

var dict2: [String: AnyObject] = [
    kRequest: [
        kTargetUserId: userId
    ]
]

如何将两个字典组合成一个新字典,如下图所示?

let parameters: [String: AnyObject] = [
    kFacebook: [
        kToken: token
    ],
    kRequest: [
        kTargetUserId: userId
    ]
]

我尝试过dict1 += dict2,但出现编译错误:

二元运算符“+=”不能应用于两个“[String : AnyObject]”操作数

【问题讨论】:

标签: ios json xcode dictionary swift


【解决方案1】:

我喜欢这种方法:

dicFrom.forEach { (key, value) in dicTo[key] = value }

Swift 4 和 5

随着 Swift 4,Apple 引入了一种更好的方法来合并两个字典:

let dictionary = ["a": 1, "b": 2]
let newKeyValues = ["a": 3, "b": 4]

let keepingCurrent = dictionary.merging(newKeyValues) { (current, _) in current }
// ["b": 2, "a": 1]

let replacingCurrent = dictionary.merging(newKeyValues) { (_, new) in new }
// ["b": 4, "a": 3]

这里有 2 个选项(与大多数在容器上运行的函数一样):

  • merge 改变现有字典
  • merging 返回一个新字典

【讨论】:

  • 这很棒。它允许选择整个字典。有没有办法添加自定义 per key 逻辑?
  • 你能发布一个链接到例如一个 github 要点来说明你想要什么(或解释:))?
  • 谢谢,非常有帮助:)
【解决方案2】:
var d1 = ["a": "b"]
var d2 = ["c": "e"]

extension Dictionary {
    mutating func merge(dict: [Key: Value]){
        for (k, v) in dict {
            updateValue(v, forKey: k)
        }
    }
}

d1.merge(d2)

参考很棒的美元和美分项目 https://github.com/ankurp/Cent/blob/master/Sources/Dictionary.swift

【讨论】:

  • 我可以将extension 放在哪里,以便在我的代码中的任何位置使用这个function?对不起,我是菜鸟!
  • 放到你项目的任意文件中
  • 如果值也是字典,怎么deep merge?
  • @RodrigoRuiz 我不认为这有什么区别,只要你的原始字典也是相同的架构,它不会有区别(除非原始字典的类型为[Key: Any] )
  • 不再需要扩展,因为Dictionary 有自己的合并功能。见stackoverflow.com/a/43615143/971329
【解决方案3】:

对于 Swift >= 2.2:
let parameters = dict1.reduce(dict2) { r, e in var r = r; r[e.0] = e.1; return r }

对于 Swift let parameters = dict1.reduce(dict2) { (var r, e) in r[e.0] = e.1; return r }

Swift 4 有一个新功能: let parameters = dict1.reduce(into: dict2) { (r, e) in r[e.0] = e.1 }

挖掘标准库非常重要:mapreducedropFirstforEach 等是简洁代码的主要内容。功能位很有趣!

【讨论】:

  • Swift 2.2 编译器抛出警告:“'var' 参数已弃用,将在 Swift 3 中删除”
【解决方案4】:

我们可以使用merge关键字更好地合并字典

var dictionary = ["a": 1, "b": 2]
/// Keeping existing value for key "a":
dictionary.merge(["a": 3, "c": 4]) { (current, _) in current }
 // ["b": 2, "a": 1, "c": 4]

【讨论】:

  • 为什么要合并新字典并保留旧值?
  • 弱一致性?
【解决方案5】:
extension Dictionary {
    static func +=(lhs: inout Self, rhs: Self) {
        lhs.merge(rhs) { _ , new in new }
    }
    static func +=<S: Sequence>(lhs: inout Self, rhs: S) where S.Element == (Key, Value) {
        lhs.merge(rhs) { _ , new in new }
    }
}

var dic = ["test1": 1]
dic += ["test2": 2]
dic  // ["test1": 1, "test2": 2]
dic += [("test2", 3),("test3", 4)]
dic  // ["test3": 4, "test1": 1, "test2": 3]

【讨论】:

    【解决方案6】:

    SequenceType.forEach(由Dictionary 实现)提供了一种优雅的解决方案,可以将字典的元素添加到另一个字典。

    dic1.forEach { dic2[$0] = $1 }
    

    例如

    func testMergeDictionaries() {
        let dic1 = [1:"foo"]
        var dic2 = [2:"bar"]
    
        dic1.forEach { dic2[$0] = $1 }
    
        XCTAssertEqual(dic2[1], "foo")
    }
    

    【讨论】:

      【解决方案7】:

      我的需求不同,我想合并而不是破坏。

      merging:
          ["b": [1, 2], "s": Set([5, 6]), "a": 1, "d": ["x": 2]]
      with
          ["b": [3, 4], "s": Set([6, 7]), "a": 2, "d": ["y": 4]]
      yields:
          ["b": [1, 2, 3, 4], "s": Set([5, 6, 7]), "a": 2, "d": ["y": 4, "x": 2]]
      

      我希望有一个更简单的解决方案,但这就是我最终得到的。挑战在于从动态类型转换到静态类型,我使用协议来解决这个问题。

      另外值得注意的是,当您使用字典字面量语法时,您实际上获得了基础类型,它不采用协议扩展。我放弃了支持这些的努力,因为我找不到一个简单的方法来验证集合元素的一致性。

      import UIKit
      
      
      private protocol Mergable {
          func mergeWithSame<T>(right: T) -> T?
      }
      
      
      
      public extension Dictionary {
      
          /**
          Merge Dictionaries
      
          - Parameter left: Dictionary to update
          - Parameter right:  Source dictionary with values to be merged
      
          - Returns: Merged dictionay
          */
      
      
          func merge(right:Dictionary) -> Dictionary {
              var merged = self
              for (k, rv) in right {
      
                  // case of existing left value
                  if let lv = self[k] {
      
                      if let lv = lv as? Mergable where lv.dynamicType == rv.dynamicType {
                          let m = lv.mergeWithSame(rv)
                          merged[k] = m
                      }
      
                      else if lv is Mergable {
                          assert(false, "Expected common type for matching keys!")
                      }
      
                      else if !(lv is Mergable), let _ = lv as? NSArray {
                          assert(false, "Dictionary literals use incompatible Foundation Types")
                      }
      
                      else if !(lv is Mergable), let _ = lv as? NSDictionary {
                          assert(false, "Dictionary literals use incompatible Foundation Types")
                      }
      
                      else {
                          merged[k] = rv
                      }
                  }
      
                      // case of no existing value
                  else {
                      merged[k] = rv
                  }
              }
      
              return merged
          }
      }
      
      
      
      
      extension Array: Mergable {
      
          func mergeWithSame<T>(right: T) -> T? {
      
              if let right = right as? Array {
                  return (self + right) as? T
              }
      
              assert(false)
              return nil
          }
      }
      
      
      extension Dictionary: Mergable {
      
          func mergeWithSame<T>(right: T) -> T? {
      
              if let right = right as? Dictionary {
                  return self.merge(right) as? T
              }
      
              assert(false)
              return nil
          }
      }
      
      
      extension Set: Mergable {
      
          func mergeWithSame<T>(right: T) -> T? {
      
              if let right = right as? Set {
                  return self.union(right) as? T
              }
      
              assert(false)
              return nil
          }
      }
      
      
      
      var dsa12 = Dictionary<String, Any>()
      dsa12["a"] = 1
      dsa12["b"] = [1, 2]
      dsa12["s"] = Set([5, 6])
      dsa12["d"] = ["c":5, "x": 2]
      
      
      var dsa34 = Dictionary<String, Any>()
      dsa34["a"] = 2
      dsa34["b"] = [3, 4]
      dsa34["s"] = Set([6, 7])
      dsa34["d"] = ["c":-5, "y": 4]
      
      
      //let dsa2 = ["a": 1, "b":a34]
      let mdsa3 = dsa12.merge(dsa34)
      print("merging:\n\t\(dsa12)\nwith\n\t\(dsa34) \nyields: \n\t\(mdsa3)")
      

      【讨论】:

        【解决方案8】:

        试试这个方法

            let dict1: [String: AnyObject] = ["kFacebook": ["kToken": "token"]]
            let dict2: [String: AnyObject] = ["kRequest": ["kTargetUserId": "userId"]]
        
            var combinedAttributes : NSMutableDictionary!
        
            combinedAttributes = NSMutableDictionary(dictionary: dict1)
        
            combinedAttributes.addEntriesFromDictionary(dict2)
        
            println(combinedAttributes)
        

        它将打印以下内容:

        {
        kFacebook =     {
            kToken = token;
        };
        kRequest =     {
            kTargetUserId = userId;
        };
        

        }

        希望对你有帮助!!

        【讨论】:

          【解决方案9】:

          您可以使用以下代码在 Swift 中组合两个字典实例:

          extension Dictionary {
              func merge(dict: Dictionary<Key,Value>) -> Dictionary<Key,Value> {
                  var mutableCopy = self
                  for (key, value) in dict {
                      // If both dictionaries have a value for same key, the value of the other dictionary is used.
                      mutableCopy[key] = value
                  }
                  return mutableCopy
              }
          }
          

          【讨论】:

          • 你应该把它重命名为merging。 merge 将是遵循 Swift 命名约定的变异版本。请注意,这两种方法已经有了原生实现。
          【解决方案10】:

          您正在使用 let 关键字来声明字典,因此您不能对字典进行更改,因为它用于声明常量。

          将其更改为 var 关键字,然后它将为您工作。

          var dict1: [String: AnyObject] = [
                      kFacebook: [
                          kToken: token
                      ]
                  ]
          
          var dict2: [String: AnyObject] = [
                  kRequest: [
                      kTargetUserId: userId
                  ]
              ]
          
          dict1 += dict2
          

          【讨论】:

            猜你喜欢
            • 2023-03-25
            • 2021-09-13
            • 2018-09-17
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-01-28
            • 1970-01-01
            相关资源
            最近更新 更多