【发布时间】:2015-01-20 04:19:13
【问题描述】:
我正在寻找一种优雅的方式来组合一系列字典。
Input: [[a: foo], [b: bar], [c: baz]]
Output: [a: foo, b: bar, c: baz]
实现这一目标的最佳方法是什么?
【问题讨论】:
标签: arrays swift dictionary
我正在寻找一种优雅的方式来组合一系列字典。
Input: [[a: foo], [b: bar], [c: baz]]
Output: [a: foo, b: bar, c: baz]
实现这一目标的最佳方法是什么?
【问题讨论】:
标签: arrays swift dictionary
您可以使用 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 没有作为任何可下标的东西传递,有什么方法可以让它工作吗?
这不是一个可怕的解决方案...
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
}
【讨论】:
我会选择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 }))
【讨论】:
使用 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"]
【讨论】:
将字典数组合并到一个字典中,用新键覆盖重复的现有键。
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 的通用版本,但很难将它表达给编译器。如果有人想尝试一下,请编辑或评论。
【讨论】:
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)
【讨论】:
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)
【讨论】:
您可以通过两次使用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)
【讨论】: