2014-11-04 27 views
21

Jak dołączyć jeden [Dictionary] do innego [Dictionary] przy użyciu Swift?Swift: jak połączyć dwie instancje Dictionary?

Używam biblioteki AlamoFire do wysyłania JSON do REST server.

słownik 1

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

Słownik 2

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

Jak mogę połączyć dwa słowniki do nowego słownika, jak pokazano poniżej?

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

Próbowałem dict1 += dict2 ale dostałem błąd kompilacji.

Z góry dziękuję!

+2

także oba dicts są stałymi (niech) to oczywiście nie można zmienić dict1 ... –

+0

Ta odpowiedź (https://stackoverflow.com/a/46542912/2020034) powinna pomóc –

Odpowiedz

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

Patrz niesamowite Dolar & projektu Cent https://github.com/ankurp/Cent/blob/master/Sources/Dictionary.swift

+0

gdzie mogę umieścić 'rozszerzenie', aby ta' funkcja' była dostępna w dowolnym miejscu mojego kodu? Przepraszam, jestem noobem! –

+1

Umieścić go w dowolnym pliku w projekcie – Shuo

+0

Co jeśli wartością jest również słownik, jak głęboko się scalić? –

-1

używasz niech słowo kluczowe aby zadeklarować słownika, więc nie można wprowadzić zmiany do słownika, gdyż służy do deklarowania stała.

Zmień na słowo kluczowe var, a następnie zadziała.

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

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

dict1 += dict2 
1

Spróbuj tego podejścia

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) 

zostanie wydrukowana następujące:

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

}

Nadzieja pomaga !!

-3
let dict1: [String: AnyObject] = [ 
    "kFacebook": [ 
     "kToken": "token" 
    ] 
] 


let dict2: [String: AnyObject] = [ 
    "kRequest": [ 
     "kTargetUserId": "userId" 
    ] 
] 

var ArrayOfDictionary = [dict1,dict2] 


println(ArrayOfDictionary) 

Ten wydrukowany

[[kFacebook: { 
    kToken = token; 
}], [kRequest: { 
    kTargetUserId = userId; 
}]] 
+3

To nie łączy dwóch słowników - po prostu tworzy tablicę z 2 słownikami – Antonio

5

SequenceType.forEach (realizowany przez Dictionary) zapewnia eleganckie rozwiązanie, aby dodać elementy słownika do innego słownika.

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

Przykładowo

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

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

    XCTAssertEqual(dic2[1], "foo") 
} 
13

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

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

To naprawdę ważne, aby kopać wokół biblioteki standardowej: map, reduce, dropFirst, forEach itp są zszywki kodu lakoniczny. Funkcjonalne bity są fajne!

+0

Kompilator Swift 2.2 generuje ostrzeżenie: parametry "var" są przestarzałe i zostaną usunięte w Swift 3 " –

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

Moje potrzeby były różne, chciałem się połączyć, a nie obijać.

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

Miałem nadzieję na prostsze rozwiązanie, ale to właśnie udało mi się uzyskać. Wyzwanie polegało na przechodzeniu od dynamicznego pisania do pisania statycznego, a ja użyłem protokołów, aby rozwiązać ten problem.

Warto również zauważyć, że przy użyciu składni literału słownikowego otrzymuje się typy fundamentów, które nie przechwytują rozszerzeń protokołu. Przerwałem moje wysiłki, by wspierać tych, ponieważ nie mogłem łatwo zweryfikować jednolitości elementów kolekcji.

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)") 
10

Kocham to podejście:

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

Swift 4

Z Swift 4 firmy Apple wprowadza lepsze podejście do scalić dwa słowniki:

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] 

You mieć 2 Opcje tutaj (jak większość funkcji działa na pojemnikach):

  • merge mutuje istniejący słownik
  • merging tworzy nowy słownik
Powiązane problemy