Swift: сгладить массив словарей в один словарь
В Swift я пытаюсь сгладить массив словарей в один словарь
то есть
let arrayOfDictionaries = [["key1": "value1"], ["key2": "value2"], ["key3": "value3", "key4": "value4"]]
//the end result will be:
flattenedArray = ["key1": "value1", "key2": "value2", "key3": "value3", "key4": "value4"]
Я попытался использовать flatmap, но тип возвращаемого результата [(String, AnyObject)]
, а не [String, Object]
, т.е.
let flattenedArray = arrayOfDictionaries.flatMap { $0 }
// type is [(String, AnyObject)]
У меня есть 2 вопроса:
-
Почему возвращается тип [(String, AnyObject)]? И что означают скобки?
-
Как достичь желаемого результата?
Изменить: я предпочел бы использовать функциональный подход с Swift map/flatmap/reduce и т.д. вместо for-loop
Ответы
Ответ 1
что означают скобки?
Это вместе с запятой вместо двоеточия должно предоставить первый ключ: скобки означают, что вы получаете массив кортежей. Поскольку вы ищете словарь, а не массив, это говорит вам, что вам нужно преобразовать последовательность кортежей (пары ключ-значение) в один словарь.
Как достичь желаемого результата?
Один из способов сделать это - использовать reduce
, например:
let flattenedDictionary = arrayOfDictionaries
.flatMap { $0 }
.reduce([String:String]()) { (var dict, tuple) in
dict.updateValue(tuple.1, forKey: tuple.0)
return dict
}
Ответ 2
В Swift 5 Dictionay
имеет init(_:uniquingKeysWith:)
. init(_:uniquingKeysWith:)
имеет следующее объявление:
init<S>(_ keysAndValues: S, uniquingKeysWith combine: (Value, Value) throws -> Value) rethrows where S : Sequence, S.Element == (Key, Value)
Создает новый словарь из пар ключ-значение в заданной последовательности, используя комбинированное замыкание для определения значения для любых повторяющихся ключей.
Два следующих примера кода Playground показывают, как сгладить массив словарей в новый словарь.
let dictionaryArray = [["key1": "value1"], ["key1": "value5", "key2": "value2"], ["key3": "value3"]]
let tupleArray: [(String, String)] = dictionaryArray.flatMap { $0 }
let dictonary = Dictionary(tupleArray, uniquingKeysWith: { (first, last) in last })
print(dictonary) // prints ["key2": "value2", "key3": "value3", "key1": "value5"]
let dictionaryArray = [["key1": 10], ["key1": 10, "key2": 2], ["key3": 3]]
let tupleArray: [(String, Int)] = dictionaryArray.flatMap { $0 }
let dictonary = Dictionary(tupleArray, uniquingKeysWith: { (first, last) in first + last })
//let dictonary = Dictionary(tupleArray, uniquingKeysWith: +) // also works
print(dictonary) // ["key2": 2, "key3": 3, "key1": 20]
Ответ 3
Обновление ответа @dasblinkenlight для Swift 3.
"var" в параметрах устарел, но этот подход работал отлично для меня.
let flattenedDictionary = arrayOfDictionaries
.flatMap { $0 }
.reduce([String:String]()) { (dict, tuple) in
var nextDict = dict
nextDict.updateValue(tuple.1, forKey: tuple.0)
return nextDict
}
Ответ 4
Вот как это сделать
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)
print(dic["key1"]!)
ВЫХОД
![OUTPUT]()