Swift: Flatten an array of dictionaries to one dictionary
在 Swift 中,我正在尝试将一组字典扁平化为一个字典
即
1
2 3 4 5 |
let arrayOfDictionaries = [[“key1″:”value1”], [“key2″:”value2”], [“key3″:”value3″,”key4″:”value4”]]
//the end result will be: |
我尝试过使用flatmap,但是返回结果的类型是[(String, AnyObject)] 而不是[String, Object] 即
1
2 |
let flattenedArray = arrayOfDictionaries.flatMap { $0 }
// type is [(String, AnyObject)] |
所以我有两个问题:
-
为什么返回类型[(String, AnyObject)]?括号是什么意思?
-
我怎样才能达到预期的效果?
编辑:我更喜欢使用 Swift 的 map/flatmap/reduce 等功能方法,而不是 for-loop
what do the brackets mean?
这与逗号而不是冒号一起应该提供第一个线索:括号意味着你得到一个元组数组。由于您要查找的是字典,而不是数组,这告诉您需要将元组序列(键值对)转换为单个字典。
How do I achieve the desired result?
一种方法是使用 reduce,如下所示:
1
2 3 4 5 6 |
let flattenedDictionary = arrayOfDictionaries
.flatMap { $0 } .reduce([String:String]()) { (var dict, tuple) in dict.updateValue(tuple.1, forKey: tuple.0) return dict } |
- 先生,您犯了一个小错误,我已修复它:) 请检查编辑
- 这里有问题 “dict.updateValue(tuple.0, forKey: tuple.1)” 我改为 dict.updateValue(tuple.1, forKey: tuple.0)
- 谢谢你。不过,我觉得可能有一种更优雅的方式。你知道为什么 flatmap 将它映射到一个元组数组而不是一个字典数组吗?
- @Lneuner 是的, (String, AnyObject) 在 Swift 的类型表示法中表示一个元组。地图将使用方括号和冒号,即 [String:AnyObject]。
- @dasblinkenlight 但为什么将其映射到元组而不是字典?
- @Lneuner 因为 map/flatMap 迭代字典。当字典被迭代时,字典中的每个项目都作为 (key, value) 元组返回。这在文档底部进行了描述。
- @dasblinkenlight 谢谢!这回答了我的问题
- @dasblinkenlight 还有一件事。我对 [String:String]()) { (var dict, tuple) 在闭包中实际做了什么感到有些困惑。您能否指出我可以阅读更多相关信息的好资源? :)
- @Lneuner reduce 需要两件事 – 结果的”初始值”,以及将当前元素”添加”到结果中的函数。在这种情况下, reduce 以一个空字典开头,因此是 [String:String]() 构造函数。 (var dict, tuple) 是将当前元组添加到字典的 lambda 函数的标头。
- @dasblinkenlight 很好的解释!谢谢!
在 Swift 5 中,Dictionay 有一个 init(_:uniquingKeysWith:) 初始化器。 init(_:uniquingKeysWith:) 具有以下声明:
1
|
init(_ keysAndValues: S, uniquingKeysWith combine: (Value, Value) throws -> Value) rethrows where S : Sequence, S.Element == (Key, Value)
|
Creates a new dictionary from the key-value pairs in the given sequence, using a combining closure to determine the value for any duplicate keys.
以下两个 Playground 示例代码展示了如何将字典数组展平为新字典。
1
2 3 4 5 6 |
let dictionaryArray = [[“key1″:”value1”], [“key1″:”value5″,”key2″:”value2”], [“key3″:”value3”]]
let tupleArray: [(String, String)] = dictionaryArray.flatMap { $0 } print(dictonary) // prints [“key2″:”value2″,”key3″:”value3″,”key1″:”value5”] |
1
2 3 4 5 6 7 |
let dictionaryArray = [[“key1”: 10], [“key1″: 10,”key2”: 2], [“key3”: 3]]
let tupleArray: [(String, Int)] = dictionaryArray.flatMap { $0 } print(dictonary) // [“key2″: 2,”key3″: 3,”key1”: 20] |
- 为什么这些 Swift 4 特性是为”从 (key, value) 元组序列初始化”而不是(或同时)而不是”字典序列”而构建的?这会强制在代码中包含 tupleArray 步骤,这有点烦人。
更新@dasblinkenlight 对 Swift 3 的回答。
参数中的”var”已被弃用,但这种方法对我来说效果很好。
1
2 3 4 5 6 7 |
let flattenedDictionary = arrayOfDictionaries
.flatMap { $0 } .reduce([String:String]()) { (dict, tuple) in var nextDict = dict nextDict.updateValue(tuple.1, forKey: tuple.0) return nextDict } |
- nextDict 应该是 var 而不是 let
这里是做
的方法
1
2 3 4 5 6 7 8 9 10 11 12 13 |
let arrayOfDictionaries = [[“key1″:”value1”], [“key2″:”value2”], [“key3″:”value3″,”key4″:”value4”]]
var dic = [String: String]() for item in arrayOfDictionaries { for (kind, value) in item { print(kind) dic.updateValue(value, forKey: kind) }
} print(dic[“key1”]!) |
OUTPUT
- 谢谢你。虽然这种方法是正确的,但我更愿意对 Swift 的 map/flatmap/reduce 等使用函数式方法。
来源:https://www.codenong.com/35597850/