Comment ajouter un Dictionary
à un autre Dictionary
en utilisant Swift
?
J'utilise la bibliothèque AlamoFire
pour envoyer un JSON
à un REST server
.
Dictionnaire 1
var dict1: [String: AnyObject] = [
kFacebook: [
kToken: token
]
]
Dictionnaire 2
var dict2: [String: AnyObject] = [
kRequest: [
kTargetUserId: userId
]
]
Comment combiner les deux dictionnaires pour créer un nouveau dictionnaire comme indiqué ci-dessous?
let parameters: [String: AnyObject] = [
kFacebook: [
kToken: token
],
kRequest: [
kTargetUserId: userId
]
]
J'ai essayé dict1 += dict2
mais a obtenu une erreur de compilation:
L'opérateur binaire '+ =' ne peut pas être appliqué à deux opérandes '[String: AnyObject]'
var d1 = ["a": "b"]
var d2 = ["c": "e"]
extension Dictionary {
mutating func merge(dict: [Key: Value]){
for (k, v) in dict {
updateValue(v, forKey: k)
}
}
}
d1.merge(d2)
Reportez-vous au génial projet Dollar & Cent https://github.com/ankurp/Cent/blob/master/Sources/Dictionary.Swift
J'adore cette approche:
dicFrom.forEach { (key, value) in dicTo[key] = value }
Swift 4 et 5
Avec Swift 4 Apple introduit une meilleure approche pour fusionner deux dictionnaires:
let dictionary = ["a": 1, "b": 2]
let newKeyValues = ["a": 3, "b": 4]
let keepingCurrent = dictionary.merging(newKeyValues) { (current, _) in current }
// ["b": 2, "a": 1]
let replacingCurrent = dictionary.merging(newKeyValues) { (_, new) in new }
// ["b": 4, "a": 3]
Vous avez 2 options ici (comme avec la plupart des fonctions fonctionnant sur des conteneurs):
merge
mute un dictionnaire existantmerging
renvoie un nouveau dictionnairePour Swift> = 2.2:let parameters = dict1.reduce(dict2) { r, e in var r = r; r[e.0] = e.1; return r }
Pour Swift <2.2:let parameters = dict1.reduce(dict2) { (var r, e) in r[e.0] = e.1; return r }
Swift 4 a une nouvelle fonction: let parameters = dict1.reduce(into: dict2) { (r, e) in r[e.0] = e.1 }
Il est très important de creuser autour de la bibliothèque standard: map
, reduce
, dropFirst
, forEach
etc. sont des agrafes de code laconique. Les bits fonctionnels sont amusants!
SequenceType.forEach
(implémenté par Dictionary
) fournit une solution élégante pour ajouter les éléments d'un dictionnaire à un autre dictionnaire.
dic1.forEach { dic2[$0] = $1 }
Par exemple
func testMergeDictionaries() {
let dic1 = [1:"foo"]
var dic2 = [2:"bar"]
dic1.forEach { dic2[$0] = $1 }
XCTAssertEqual(dic2[1], "foo")
}
func +=<Key, Value> (lhs: inout [Key: Value], rhs: [Key: Value]) {
rhs.forEach{ lhs[$0] = $1 }
}
var dic1 = ["test1": 1]
dic1 += ["test2": 2]
dic1 // ["test2": 2, "test1": 1]
Mes besoins étaient différents, je voulais fusionner et non clobber.
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]]
J'espérais une solution plus simple, mais c'est ce avec quoi je me suis retrouvé. Le défi consistait à passer du typage dynamique au typage statique, et j'ai utilisé des protocoles pour résoudre ce problème.
Il convient également de noter que lorsque vous utilisez la syntaxe littérale du dictionnaire, vous obtenez en fait les types de fondation, qui ne récupèrent pas les extensions de protocole. J'ai avorté mes efforts pour les soutenir car je n'ai pas pu trouver un moyen facile de valider l'uniformité des éléments de la collection.
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)")
Essayez cette approche
let dict1: [String: AnyObject] = ["kFacebook": ["kToken": "token"]]
let dict2: [String: AnyObject] = ["kRequest": ["kTargetUserId": "userId"]]
var combinedAttributes : NSMutableDictionary!
combinedAttributes = NSMutableDictionary(dictionary: dict1)
combinedAttributes.addEntriesFromDictionary(dict2)
println(combinedAttributes)
Il imprimera ce qui suit:
{
kFacebook = {
kToken = token;
};
kRequest = {
kTargetUserId = userId;
};
}
J'espère que ça aide !!
Vous pouvez utiliser le code ci-dessous pour combiner deux instances de dictionnaire dans Swift:
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
}
}