web-dev-qa-db-fra.com

Comment combiner deux instances de dictionnaire dans Swift?

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]'

49
The Nomad
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

40
Shuo

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 existant
  • merging renvoie un nouveau dictionnaire
82
blackjacx

Pour 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!

14
emp

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")
}
5
rhooke
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]
4
Leo Dabus

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)")
2
Chris Conover

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 !!

2
Wolverine

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
    }
}
0
Pallavi