Wie kombiniere ich zwei Dictionary-Instanzen in Swift?

81

Wie anhängen ich eine Dictionaryan eine andere DictionaryVerwendung Swift?

Ich benutze die AlamoFireBibliothek, um a JSONan a zu senden REST server.

Wörterbuch 1

var dict1: [String: AnyObject] = [
        kFacebook: [
            kToken: token
        ]
    ]

Wörterbuch 2

var dict2: [String: AnyObject] = [
        kRequest: [
            kTargetUserId: userId
        ]
    ]

Wie kombiniere ich die beiden Wörterbücher, um ein neues Wörterbuch zu erstellen, wie unten gezeigt?

let parameters: [String: AnyObject] = [
        kFacebook: [
            kToken: token
        ],
        kRequest: [
            kTargetUserId: userId
        ]
    ]

Ich habe es versucht, dict1 += dict2aber einen Kompilierungsfehler erhalten:

Der Binäroperator '+ =' kann nicht auf zwei '[String: AnyObject]' - Operanden angewendet werden

Der Nomade
quelle
Hey @ the-nomad, könntest du deine akzeptierte Antwort auf die mit mehr als doppelten Upvotes verschieben - bitte :-)?
Blackjacx

Antworten:

61
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)

Weitere Informationen finden Sie im großartigen Dollar & Cent-Projekt https://github.com/ankurp/Cent/blob/master/Sources/Dictionary.swift

Shuo
quelle
Wo kann ich das platzieren extension, um functiones irgendwo in meinem Code verfügbar zu haben ? Entschuldigung, ich bin ein Noob!
Der Nomade
1
Legen Sie es in eine beliebige Datei in Ihrem Projekt
Shuo
Was ist, wenn der Wert auch ein Wörterbuch ist? Wie verschmelzen Sie tief?
Rodrigo Ruiz
@ RodrigoRuiz Ich glaube nicht, dass es einen Unterschied macht, solange Ihr ursprüngliches Wörterbuch auch die gleiche Architektur hat, wird es keinen Unterschied machen (es sei denn, das ursprüngliche Wörterbuch ist vom Typ [Key: Any])
Septronic
1
Die Erweiterung wird nicht mehr benötigt, da sie über Dictionaryeigene Zusammenführungsfunktionen verfügt. Siehe stackoverflow.com/a/43615143/971329 .
Blackjacx
153

Ich liebe diesen Ansatz:

dicFrom.forEach { (key, value) in dicTo[key] = value }

Swift 4 und 5

Mit Swift 4 führt Apple einen besseren Ansatz zum Zusammenführen von zwei Wörterbüchern ein:

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]

Sie haben hier zwei Möglichkeiten (wie bei den meisten Funktionen, die mit Containern ausgeführt werden):

  • merge mutiert ein vorhandenes Wörterbuch
  • merging gibt ein neues Wörterbuch zurück
blackjacx
quelle
16

Für Swift> = 2.2:
let parameters = dict1.reduce(dict2) { r, e in var r = r; r[e.0] = e.1; return r }

Für Swift <2.2:
let parameters = dict1.reduce(dict2) { (var r, e) in r[e.0] = e.1; return r }

Swift 4 hat eine neue Funktion: let parameters = dict1.reduce(into: dict2) { (r, e) in r[e.0] = e.1 }

Es ist wirklich wichtig , um die Standard - Bibliothek wühlen: map, reduce, dropFirst, forEachusw. sind Heftklammern des lapidaren Code. Die funktionalen Teile machen Spaß!

emp
quelle
Swift 2.2 Compiler gibt eine Warnung aus: "'var' Parameter sind veraltet und werden in Swift 3 entfernt"
Dheeraj Vepakomma
7

SequenceType.forEach(implementiert von Dictionary) bietet eine elegante Lösung, um die Elemente eines Wörterbuchs einem anderen Wörterbuch hinzuzufügen.

dic1.forEach { dic2[$0] = $1 }

Zum Beispiel

func testMergeDictionaries() {
    let dic1 = [1:"foo"]
    var dic2 = [2:"bar"]

    dic1.forEach { dic2[$0] = $1 }

    XCTAssertEqual(dic2[1], "foo")
}
Rhooke
quelle
7
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]
Leo Dabus
quelle
4

Mit dem Schlüsselwort merge können wir Wörterbücher besser zusammenführen

var dictionary = ["a": 1, "b": 2]
/// Keeping existing value for key "a":
dictionary.merge(["a": 3, "c": 4]) { (current, _) in current }
 // ["b": 2, "a": 1, "c": 4]
Raja Jawahar
quelle
3

Meine Bedürfnisse waren anders, ich wollte verschmelzen und nicht überfallen.

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

Ich hatte auf eine einfachere Lösung gehofft, aber damit bin ich gelandet. Die Herausforderung bestand darin, von der dynamischen zur statischen Typisierung zu wechseln, und ich habe Protokolle verwendet, um dies zu lösen.

Bemerkenswert ist auch, dass Sie bei Verwendung der Wörterbuch-Literal-Syntax tatsächlich die Grundlagentypen erhalten, die die Protokollerweiterungen nicht übernehmen. Ich habe meine Bemühungen, diese zu unterstützen, abgebrochen, da ich keine einfache Möglichkeit fand, die Einheitlichkeit der Sammlungselemente zu überprüfen.

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

Versuchen Sie diesen Ansatz

    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)

Es wird Folgendes gedruckt:

{
kFacebook =     {
    kToken = token;
};
kRequest =     {
    kTargetUserId = userId;
};

}}

Ich hoffe es hilft !!

Vielfraß
quelle
1

Mit dem folgenden Code können Sie zwei Wörterbuchinstanzen in Swift kombinieren:

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
    }
}
Pallavi
quelle
-1

Sie verwenden das Schlüsselwort let, um das Wörterbuch zu deklarieren, sodass Sie keine Änderungen an Ihrem Wörterbuch vornehmen können, da es zum Deklarieren von Konstanten verwendet wird.

Ändern Sie es in das Schlüsselwort var, dann funktioniert es für Sie.

var dict1: [String: AnyObject] = [
            kFacebook: [
                kToken: token
            ]
        ]

var dict2: [String: AnyObject] = [
        kRequest: [
            kTargetUserId: userId
        ]
    ]

dict1 += dict2
Meenakshi
quelle