【问题标题】:Swift: Combine Dictionaries in an ArraySwift:将字典组合成一个数组
【发布时间】:2015-01-20 04:19:13
【问题描述】:

我正在寻找一种优雅的方式来组合一系列字典。

Input: [[a: foo], [b: bar], [c: baz]]
Output: [a: foo, b: bar, c: baz]

实现这一目标的最佳方法是什么?

【问题讨论】:

    标签: arrays swift dictionary


    【解决方案1】:

    您可以使用 reduce,但您必须定义一个“组合”方法,该方法将为您提供来自 2 个单独字典的组合字典。

    所以你可以做这样的事情

    let inputArray = [["a": "foo"], ["b": "bar"], ["c": "baz"], ["c": "bazx"]]
    let flat = inputArray.reduce([:]) { $0 + $1 }
    

    如果你在字典上重载了“+”

    func + <K, V>(lhs: [K : V], rhs: [K : V]) -> [K : V] {
        var combined = lhs
    
        for (k, v) in rhs {
            combined[k] = v
        }
    
        return combined
    }
    

    【讨论】:

    • 是否可以一步完成?我在想var output = dict.reduce([:]) { (var combined, current) in combined[current[0]] = current[1] } 的某个地方,但很明显,vars 没有作为任何可下标的东西传递,有什么方法可以让它工作吗?
    【解决方案2】:

    这不是一个可怕的解决方案...

    let inputArray = [["a": "foo"], ["b": "bar"], ["c": "baz"]]
    
    let inputArrayFlat = inputArray.reduce([String:String]()) {
        var output = $0
        for (key, value) in $1 { output[key] = value }
        return output
    }
    

    【讨论】:

      【解决方案3】:

      我会选择Dictionary 分机:

      extension Dictionary {
          init<S: SequenceType where Element == S.Generator.Element>(_ s:S) {
              self.init()
              var g = s.generate()
              while let e: Element = g.next() {
                  self[e.0] = e.1
              }
          }
      }
      

      使用此扩展,您可以使用一系列 (Key, Value) 对来初始化 Dictionary。所以你可以:

      let input = [["a": "foo"], ["b": "bar"], ["c": "baz"]]
      
      let output = Dictionary(input.reduce([], { $0 + $1 }))
      

      【讨论】:

        【解决方案4】:

        使用 Swift 4.2 的另一种方法:

        let inputArray = [["a": "foo"], ["b": "bar"], ["c": "baz"], ["c": "bazx"]]
        let result = inputArray.flatMap { $0 }.reduce([:]) { $0.merging($1) { (current, _) in current } }
        

        输出:

        ["b": "bar", "c": "baz", "a": "foo"]
        

        【讨论】:

          【解决方案5】:

          将字典数组合并到一个字典中,用新键覆盖重复的现有键。

          extension Array where Element == [String:String] {
              func merged() -> [String:String] {
                  reduce(into: [String:String]()) { $0.merge($1) { $1 } }
              }        
          }
          

          [[String:String]] 变成一个[String:String]

          let test = [["a":"1", "b":"2"], ["a":"3", "c":"4"]]
          assert(test.merged() == ["a":"3", "b":"2", "c":"4"])
          

          我想要一个不依赖于String 的通用版本,但很难将它表达给编译器。如果有人想尝试一下,请编辑或评论。

          【讨论】:

            【解决方案6】:
            let inputArray = [["a": "foo"], ["b": "bar"], ["c": "baz"], ["c": "bazx"]]
            
            var flat = [String:String]()
            for e in inputArray {
                for (k, v) in e {
                    flat[k] = v
                }
            }
            
            dump(flat)
            

            【讨论】:

            • 虽然这确实有效,但我一直在寻找更短一点的东西,比如 map() 或连接函数。
            • 我明白,但我认为目前 Swift 词典还无法做到这一点。
            • 有一系列有趣的替代方法,但值得注意的是,这是最有效的方法之一。对它们进行基准测试,您会看到非凡的性能范围。
            【解决方案7】:
            let inputArray = [["a": "foo"], ["b": "bar"], ["c": "baz"]].reduce([], +)
            var result:[String:String] = [:]
            for item in inputArray {
                result.updateValue(item.1, forKey: item.0)
            }
            println(result.description)
            

            【讨论】:

              【解决方案8】:

              您可以通过两次使用reduce 来做到这一点——一次在外部数组上,一次在处理内部字典时。如果任何字典有重复的键,此版本将只保留该键的最后一个值。

              func flattenDictionaryList<T, U>(list: [[T: U]]) -> [T: U] {
                  return list.reduce([:]) { combined, current in
                      reduce(current, combined) { (var innerCombined: [T: U], innerCurrent: (key: T, value: U)) in
                          innerCombined[innerCurrent.key] = innerCurrent.value
                          return innerCombined
                      }
                  }
              }
              
              let input = [["a": "foo"], ["b": "bar"], ["c": "baz"]]
              let output = flattenDictionaryList(input)
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2015-10-04
                • 2012-05-20
                • 1970-01-01
                • 2018-10-05
                • 2020-07-29
                • 2019-10-26
                • 2018-11-14
                • 2019-07-03
                相关资源
                最近更新 更多