Làm thế nào để kết hợp hai phiên bản Từ điển trong Swift?


81

Làm cách nào để nối cái này Dictionaryvới cái khác Dictionarybằng cách sử dụng Swift?

Tôi đang sử dụng AlamoFirethư viện để gửi JSONa REST server.

Từ điển 1

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

Từ điển 2

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

Làm cách nào để kết hợp hai từ điển để tạo một từ điển mới như hình dưới đây?

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

Tôi đã thử dict1 += dict2nhưng gặp lỗi biên dịch:

Toán tử nhị phân '+ =' không thể áp dụng cho hai toán hạng '[String: AnyObject]'




Này @ the-nomad, bạn có thể chuyển câu trả lời được chấp nhận của mình sang câu trả lời có nhiều hơn gấp đôi số phiếu ủng hộ không - vui lòng :-)?
blackjacx

Câu trả lời:


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)

Tham khảo dự án Dollar & Cent tuyệt vời https://github.com/ankurp/Cent/blob/master/Sources/Dictionary.swift


Tôi có thể đặt ở đâu extensionđể có cái này functionở bất kỳ đâu trong mã của tôi? Xin lỗi, tôi là một noob!
The Nomad

1
Đặt nó vào bất kỳ tệp nào trong dự án của bạn
Shuo

Điều gì sẽ xảy ra nếu giá trị cũng là một từ điển, làm thế nào để bạn hợp nhất sâu?
Rodrigo Ruiz

@RodrigoRuiz Tôi không nghĩ rằng nó làm cho bất kỳ sự khác biệt, miễn là từ điển ban đầu của bạn cũng là kiến trúc tương tự, nó sẽ không tạo sự khác biệt (trừ trường hợp điển ban đầu là loại [Key: Any])
Septronic

2
Phần mở rộng không cần thiết nữa vì Dictionaryđã có các chức năng hợp nhất của riêng nó. Xem stackoverflow.com/a/43615143/971329 .
blackjacx

154

Tôi thích cách tiếp cận này:

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

Swift 4 và 5

Với Swift 4, Apple giới thiệu một cách tiếp cận tốt hơn để hợp nhất hai từ điển:

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]

Bạn có 2 tùy chọn ở đây (như với hầu hết các chức năng hoạt động trên vùng chứa):

  • merge thay đổi một từ điển hiện có
  • merging trả về một từ điển mới

16

Đối với Swift> = 2.2:
let parameters = dict1.reduce(dict2) { r, e in var r = r; r[e.0] = e.1; return r }

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

Swift 4 có một chức năng mới: let parameters = dict1.reduce(into: dict2) { (r, e) in r[e.0] = e.1 }

Đó là thực sự quan trọng để đào xung quanh thư viện tiêu chuẩn: map, reduce, dropFirst, forEachvv là mặt hàng chủ lực của súc tích mã. Các bit chức năng rất thú vị!


Swift 2.2 trình biên dịch ném một cảnh báo: " 'var' tham số được chấp nhận và sẽ được loại bỏ trong Swift 3"
Dheeraj Vepakomma

7

SequenceType.forEach(được thực hiện bởi Dictionary) cung cấp một giải pháp thanh lịch để thêm các phần tử của từ điển vào từ điển khác.

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

Ví dụ

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

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

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

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]

4

Chúng tôi có thể hợp nhất các từ điển theo cách tốt hơn bằng cách sử dụng từ khóa hợp nhất

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

Nhu cầu của tôi đã khác, tôi muốn hợp nhất chứ không muốn làm gián đoạn.

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

Tôi đã hy vọng một giải pháp đơn giản hơn, nhưng đây là những gì tôi đã kết thúc. Thách thức là chuyển từ nhập động sang nhập tĩnh và tôi đã sử dụng các giao thức để giải quyết vấn đề này.

Cũng đáng lưu ý là khi bạn sử dụng cú pháp theo nghĩa đen từ điển, bạn thực sự nhận được các loại nền tảng, mà không nhận các phần mở rộng giao thức. Tôi đã hủy bỏ những nỗ lực của mình để hỗ trợ những người đó vì tôi không thể tìm thấy cách dễ dàng để xác nhận tính đồng nhất của các thành phần trong bộ sưu tập.

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

Hãy thử cách tiếp cận này

    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)

Nó sẽ in như sau:

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

}

Hy vọng nó giúp !!


1

Bạn có thể sử dụng đoạn mã dưới đây để kết hợp hai phiên bản từ điển trong 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

Bạn đang sử dụng từ khóa let để khai báo từ điển nên bạn không thể thực hiện các thay đổi đối với từ điển của mình vì nó được sử dụng để khai báo hằng số.

Thay đổi nó thành từ khóa var sau đó nó sẽ hoạt động cho bạn.

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

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

dict1 += dict2
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.