Як поєднати два екземпляри словника в Swift?


87

Як я додаю одне Dictionaryдо іншого Dictionaryза допомогою Swift?

Я використовую AlamoFireбібліотеку для надсилання JSONфайлу REST server.

Словник 1

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

Словник 2

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

Як поєднати два словники, щоб створити новий словник, як показано нижче?

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

Я спробував, dict1 += dict2але отримав помилку компіляції:

Двійковий оператор '+ =' не можна застосувати до двох операндів '[String: AnyObject]'




Привіт @ the-nomad, чи не міг би ти перенести прийняту відповідь на ту, що має більше ніж подвійні голоси - будь ласка :-)?
blackjacx

Відповіді:


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

Зверніться до чудового проекту Dollar & Cent https://github.com/ankurp/Cent/blob/master/Sources/Dictionary.swift


де я можу поставити, extensionщоб це було functionдоступно в будь-якому місці мого коду? Вибачте, я нуб!
Кочівник

1
Помістіть його в будь-який файл у своєму проекті
Шуо,

Що робити, якщо значення - це також словник, як глибоко злити?
Родріго Руїс,

@RodrigoRuiz Я не думаю, що це має різницю, якщо ваш оригінальний словник також має однакову архітектуру, він не матиме значення (якщо оригінальний словник не має типу [Key: Any])
Septronic,

2
Розширення більше не потрібне, оскільки воно Dictionaryмає власні функції злиття. Див. Stackoverflow.com/a/43615143/971329 .
blackjacx

161

Мені подобається такий підхід:

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

Свіфт 4 і 5

За допомогою Swift 4 Apple пропонує кращий підхід до об’єднання двох словників:

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]

Тут є 2 варіанти (як і у більшості функцій, що працюють на контейнерах):

  • merge мутує існуючий словник
  • merging повертає новий словник

16

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

Для Свіфта <2.2:
let parameters = dict1.reduce(dict2) { (var r, e) in r[e.0] = e.1; return r }

Swift 4 має нову функцію: let parameters = dict1.reduce(into: dict2) { (r, e) in r[e.0] = e.1 }

Це дуже важливо , щоб вирити навколо стандартної бібліотеки: map, reduce, dropFirst, і forEachт.д., головні продукти небагатослівний коду. Функціональні біти - це весело!


Компілятор Swift 2.2 видає попередження: "Параметри 'var' застаріли та будуть видалені в Swift 3"
Dheeraj Vepakomma,

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

7

SequenceType.forEach(реалізований Dictionary) надає елегантне рішення для додавання елементів словника до іншого словника.

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

Наприклад

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

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

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

6

Ми можемо об’єднати словники кращим чином, використовуючи ключове слово merge

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]

3

Мої потреби були різними, я хотів об’єднатись, а не клаббер.

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

Я сподівався на більш просте рішення, але це те, з чим я закінчив. Проблема полягала в переході від динамічного набору до статичного набору тексту, і я використовував протоколи, щоб вирішити це.

Також варто зазначити, що коли ви використовуєте синтаксис словника буквально, ви фактично отримуєте основні типи, які не забирають розширення протоколу. Я припинив свої зусилля, щоб підтримати таких, оскільки не міг знайти легкого для перевірки однорідності елементів колекції.

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

Спробуйте цей підхід

    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)

Буде надруковано наступне:

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

}

Сподіваюся, це допоможе !!


1

Ви можете використовувати наведений нижче код, щоб об’єднати два екземпляри словника в 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
    }
}

-1

Ви використовуєте ключове слово let для оголошення словника, тому ви не можете вносити зміни до свого словника, оскільки він використовується для оголошення константи.

Змініть його на ключове слово var, тоді воно буде працювати для вас.

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

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

dict1 += dict2
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.