Как добавить словарь элементов в другой словарь
массивы в Swift поддерживают оператор += для добавления содержимого одного массива в другой. Есть ли простой способ сделать это для словаря?
например:
var dict1 = ["a" : "foo"]
var dict2 = ["b" : "bar"]
var combinedDict = ... (some way of combining dict1 & dict2 without looping)
25 ответов:
вы можете определить
+=оператораDictionary, например,func += <K, V> (left: inout [K:V], right: [K:V]) { for (k, v) in right { left[k] = v } }
В настоящее время, глядя на Ссылка На Стандартную Библиотеку Swift для словаря, нет никакого способа, чтобы легко обновить словарь с другом.
вы можете написать расширение для этого
var dict1 = ["a" : "foo"] var dict2 = ["b" : "bar"] extension Dictionary { mutating func update(other:Dictionary) { for (key,value) in other { self.updateValue(value, forKey:key) } } } dict1.update(dict2) // dict1 is now ["a" : "foo", "b" : "bar]
в Swift 4 следует использовать
merging(_:uniquingKeysWith:):пример:
let dictA = ["x" : 1, "y": 2, "z": 3] let dictB = ["x" : 11, "y": 22, "w": 0] let resultA = dictA.merging(dictB, uniquingKeysWith: { (first, _) in first }) let resultB = dictA.merging(dictB, uniquingKeysWith: { (_, last) in last }) print(resultA) // ["x": 1, "y": 2, "z": 3, "w": 0] print(resultB) // ["x": 11, "y": 22, "z": 3, "w": 0]
Он не встроен в библиотеку Swift, но вы можете добавить то, что хотите, с перегрузкой оператора, например:
func + <K,V>(left: Dictionary<K,V>, right: Dictionary<K,V>) -> Dictionary<K,V> { var map = Dictionary<K,V>() for (k, v) in left { map[k] = v } for (k, v) in right { map[k] = v } return map }это перегружает
+оператор для словарей, которые теперь можно использовать для добавления словарей с+оператор, например:var dict1 = ["a" : "foo"] var dict2 = ["b" : "bar"] var dict3 = dict1 + dict2 // ["a": "foo", "b": "bar"]
Swift 3:
extension Dictionary { mutating func merge(with dictionary: Dictionary) { dictionary.forEach { updateValue(, forKey: ) } } func merged(with dictionary: Dictionary) -> Dictionary { var dict = self dict.merge(with: dictionary) return dict } } let a = ["a":"b"] let b = ["1":"2"] let c = a.merged(with: b) print(c) //["a": "b", "1": "2"]
Swift 2.0
extension Dictionary { mutating func unionInPlace(dictionary: Dictionary) { dictionary.forEach { self.updateValue(, forKey: ) } } func union(var dictionary: Dictionary) -> Dictionary { dictionary.unionInPlace(self) return dictionary } }
Swift 4 предоставляет
merging(_:uniquingKeysWith:), так что для вашего случая:let combinedDict = dict1.merging(dict2) { }стенографическое закрытие возвращает
, поэтому значение dict2 будет использоваться при возникновении конфликта с ключами.
неизменяемые
Я предпочитаю объединять / объединять неизменяемые словари с
+оператор поэтому я реализовал его так:// Swift 2 func + <K,V> (left: Dictionary<K,V>, right: Dictionary<K,V>?) -> Dictionary<K,V> { guard let right = right else { return left } return left.reduce(right) { var new = as [K:V] new.updateValue(.1, forKey: .0) return new } } let moreAttributes: [String:AnyObject] = ["Function":"authenticate"] let attributes: [String:AnyObject] = ["File":"Auth.swift"] attributes + moreAttributes + nil //["Function": "authenticate", "File": "Auth.swift"] attributes + moreAttributes //["Function": "authenticate", "File": "Auth.swift"] attributes + nil //["File": "Auth.swift"]Mutable
// Swift 2 func += <K,V> (inout left: Dictionary<K,V>, right: Dictionary<K,V>?) { guard let right = right else { return } right.forEach { key, value in left.updateValue(value, forKey: key) } } let moreAttributes: [String:AnyObject] = ["Function":"authenticate"] var attributes: [String:AnyObject] = ["File":"Auth.swift"] attributes += nil //["File": "Auth.swift"] attributes += moreAttributes //["File": "Auth.swift", "Function": "authenticate"]
более читаемый вариант с использованием расширения.
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 } }
теперь не нужно иметь никаких расширений словаря. Swift (Xcode 9.0+) словарь имеет функциональность для этого. Посмотри здесь. Ниже приведен пример того, как его использовать
var oldDictionary = ["a": 1, "b": 2] var newDictionary = ["a": 10000, "b": 10000, "c": 4] oldDictionary.merge(newDictionary) { (oldValue, newValue) -> Int in // This closure return what value to consider if repeated keys are found return newValue } print(oldDictionary) // Prints ["b": 10000, "a": 10000, "c": 4]
вы можете попробовать это
var dict1 = ["a" : "foo"] var dict2 = ["b" : "bar"] var temp = NSMutableDictionary(dictionary: dict1); temp .addEntriesFromDictionary(dict2)
вы также можете использовать уменьшить, чтобы объединить их. Попробуйте это на детской площадке
let d1 = ["a":"foo","b":"bar"] let d2 = ["c":"car","d":"door"] let d3 = d1.reduce(d2) { (var d, p) in d[p.0] = p.1 return d }
рекомендую Библиотека SwifterSwift. Однако, если вы не хотите использовать всю библиотеку и все дополнения, которые вы можете просто использовать их расширение словаря:
Swift 3+
public extension Dictionary { public static func +=(lhs: inout [Key: Value], rhs: [Key: Value]) { rhs.forEach({ lhs[] = }) } }
вы можете перебирать комбинации ключевых значений ob значение, которое вы хотите объединить и добавить их с помощью метода updateValue (forKey:):
dictionaryTwo.forEach { dictionaryOne.updateValue(, forKey: ) }теперь все значения dictionaryTwo добавлены в dictionaryOne.
то же самое, что и ответ @farhadf, но принятый для Swift 3:
let sourceDict1 = [1: "one", 2: "two"] let sourceDict2 = [3: "three", 4: "four"] let result = sourceDict1.reduce(sourceDict2) { (partialResult , pair) in var partialResult = partialResult //without this line we could not modify the dictionary partialResult[pair.0] = pair.1 return partialResult }
вы можете добавить
Dictionaryрасширение такой:extension Dictionary { func mergedWith(otherDictionary: [Key: Value]) -> [Key: Value] { var mergedDict: [Key: Value] = [:] [self, otherDictionary].forEach { dict in for (key, value) in dict { mergedDict[key] = value } } return mergedDict } }затем использование как простой следующим образом:
var dict1 = ["a" : "foo"] var dict2 = ["b" : "bar"] var combinedDict = dict1.mergedWith(dict2) // => ["a": "foo", "b": "bar"]
Если вы предпочитаете платформу, которая также включает в себя некоторые более удобные функции затем оформить заказ HandySwift. Просто импортируйте его в свой проект и вы можете использовать приведенный выше код без добавления каких-либо расширений в проект себе.
The ExSwift библиотека обеспечивает объединение словарей (называется Union и определяется как оператор трубы'|'), а также множество других удобных функций для основных типов.
Swift 3, расширение словаря:
public extension Dictionary { public static func +=(lhs: inout Dictionary, rhs: Dictionary) { for (k, v) in rhs { lhs[k] = v } } }
вы можете использовать функцию bridgeToObjectiveC (), чтобы сделать словарь NSDictionary.
будет выглядеть следующим образом:
var dict1 = ["a":"Foo"] var dict2 = ["b":"Boo"] var combinedDict = dict1.bridgeToObjectiveC() var mutiDict1 : NSMutableDictionary! = combinedDict.mutableCopy() as NSMutableDictionary var combineDict2 = dict2.bridgeToObjectiveC() var combine = mutiDict1.addEntriesFromDictionary(combineDict2)затем вы можете конвертировать NSDictionary(combine) обратно или делать все, что угодно.
import Foundation let x = ["a":1] let y = ["b":2] let out = NSMutableDictionary(dictionary: x) out.addEntriesFromDictionary(y)результатом является NSMutableDictionary не Swift типизированный словарь, но синтаксис для его использования тот же (
out["a"] == 1в этом случае), поэтому у вас будет проблема только в том случае, если вы используете сторонний код, который ожидает Swift-словарь, или действительно нуждается в проверке типа.короткий ответ здесь заключается в том, что вы на самом деле должны цикл. Даже если вы не вводите его явно, это то, что будет делать вызываемый метод (addEntriesFromDictionary: here). Я бы предложил, если вы немного не понимаете, почему это было бы так, вы должны рассмотреть, как вы объединили бы листовые узлы двух B-деревьев.
Если вам действительно нужен быстрый тип родного словаря взамен, я бы предложил:
let x = ["a":1] let y = ["b":2] var out = x for (k, v) in y { out[k] = v }недостатком этого подхода является то, что индекс словаря - как бы это ни было сделано - может быть перестроен несколько раз в цикле, поэтому на практике это примерно в 10 раз медленнее, чем подход NSMutableDictionary.
все эти ответы сложно. Это мое решение для swift 2.2:
//get first dictionnary let finalDictionnary : NSMutableDictionary = self.getBasicDict() //cast second dictionnary as [NSObject : AnyObject] let secondDictionnary : [NSObject : AnyObject] = self.getOtherDict() as [NSObject : AnyObject] //merge dictionnary into the first one finalDictionnary.addEntriesFromDictionary(secondDictionnary)
Я бы просто использовать доллар библиотека.
https://github.com/ankurp/Dollar/#merge---merge-1
объединяет все словари вместе и последний словарь переопределяет значение в данном ключе
let dict: Dictionary<String, Int> = ["Dog": 1, "Cat": 2] let dict2: Dictionary<String, Int> = ["Cow": 3] let dict3: Dictionary<String, Int> = ["Sheep": 4] $.merge(dict, dict2, dict3) => ["Dog": 1, "Cat": 2, "Cow": 3, "Sheep": 4]
мои потребности были другими, мне нужно было объединить неполные вложенные наборы данных без clobbering.
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]]Это было сложнее, чем я хотел, чтобы это было. Проблема заключалась в отображении от динамического ввода до статического ввода, и я использовал протоколы для решения этой проблемы.
также стоит отметить, что при использовании словарного литерального синтаксиса вы фактически получаете типы foundation, которые не подбирают расширения протокола. Я прервал свои усилия, чтобы поддержать тех, кто не мог найти легко для проверки однородности элементов коллекции.
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)")
Swift 2.2
func + <K,V>(left: [K : V], right: [K : V]) -> [K : V] { var result = [K:V]() for (key,value) in left { result[key] = value } for (key,value) in right { result[key] = value } return result }
Comments