คุณจะเพิ่มพจนานุกรมของรายการลงในพจนานุกรมอื่นได้อย่างไร


172

อาร์เรย์ใน Swift สนับสนุนตัวดำเนินการ + = เพื่อเพิ่มเนื้อหาของ Array หนึ่งไปยังอีก มีวิธีง่ายๆในการทำเช่นนั้นสำหรับพจนานุกรมหรือไม่?

เช่น:

var dict1 = ["a" : "foo"]
var dict2 = ["b" : "bar"]

var combinedDict = ... (some way of combining dict1 & dict2 without looping)


fromDict.forEach {intoDict[$0] = $1}
Sazzad Hissain Khan

คำตอบ:


171

คุณสามารถกำหนด+=โอเปอเรเตอร์สำหรับDictionaryเช่น

func += <K, V> (left: inout [K:V], right: [K:V]) { 
    for (k, v) in right { 
        left[k] = v
    } 
}

1
โอ้มนุษย์ฉันต้องดิ้นรนมากกับการค้นหาคำประกาศทั่วไปที่เหมาะสมสำหรับเรื่องนี้ฉันลองทุกอย่างยกเว้นสิ่งนี้ แต่คุณสามารถปล่อย@assignmentและreturnคุณกลายพันธุ์ไปทางซ้ายแล้ว แก้ไข: จริง ๆ แล้วแม้ว่าฉันจะไม่มีข้อผิดพลาดฉันก็คิดว่า@assignmentควรจะอยู่ต่อไป
Roland

14
เพิ่มเติมไวยากรณ์น้ำตาล: func +=<K, V> (inout left: [K : V], right: [K : V]) { for (k, v) in right { left[k] = v } }
Ivan Vavilov

48
@animal_chin เพราะเราต้องใช้ภาษาครึ่งตัวเอง? ใช่. สร้างความประทับใจ อย่าเข้าใจฉันผิดฉันชอบผู้ให้บริการมากไป ฉันไม่ชอบที่จะใช้มันสำหรับคุณสมบัติพื้นฐานที่ควรสร้างขึ้นมา
devios1

2
@devios Haha จากนั้นให้ดึงคำขอไปยัง Swift repo: D เนื่องจาก Apple ไม่สามารถแจ้งให้ทราบได้
CommaToast

6
ดึงตรงจากห้องสมุด SwifterSwift :public static func +=(lhs: inout [Key: Value], rhs: [Key: Value]) { rhs.forEach({ lhs[$0] = $1}) }
Justin Oroz

99

ใน Swift 4 เราควรใช้merging(_:uniquingKeysWith:):

ตัวอย่าง:

let dictA = ["x" : 1, "y": 2, "z": 3]
let dictB = ["x" : 11, "y": 22, "w": 0]

let resultA = dictA.merging(dictB, uniquingKeysWith: { (first, _) in first })
let resultB = dictA.merging(dictB, uniquingKeysWith: { (_, last) in last })

print(resultA) // ["x": 1, "y": 2, "z": 3, "w": 0]
print(resultB) // ["x": 11, "y": 22, "z": 3, "w": 0]

1
// ไม่แน่นอน: var dictA = ["x": 1, "y": 2, "z": 3] var dictB = ["x": 11, "y": 22, "w": 0] dictA ผสาน (dictB, uniquingKeysWith: {(ก่อน, _) ในตอนแรก}) พิมพ์ (dictA) // ["x": 1, "y": 2, "z": 3, "w": 0]
muthukumar

1
[NSMutableDictionary addEntriesFromDictionary:]ตัวอย่างที่สองแสดงให้เห็นในคำตอบนี้เป็นเทียบเท่า
orj

92

เกี่ยวกับ

dict2.forEach { (k,v) in dict1[k] = v }

นั่นเป็นการเพิ่มคีย์และค่าของ dict2 ทั้งหมดลงใน dict1


43
ทางออกที่ดี สั้นลงเล็กน้อย: dict2.forEach {dict1 [$ 0] = $ 1}
Brett

1
นี่เป็นวิธีแก้ปัญหาที่ดี แต่สำหรับ Swift 4 คุณมักจะได้รับข้อผิดพลาดที่ระบุไว้Closure tuple parameter '(key: _, value: _)' does not support destructuring(อย่างน้อยตอนที่เขียนนี้) หนึ่งจะต้องปรับโครงสร้างการปิดตาม [คำตอบส
แต็

78

ขณะนี้เมื่อดูการอ้างอิงพจนานุกรมของSwift Standard Libraryสำหรับพจนานุกรมไม่มีวิธีที่จะง่ายต่อการอัพเดทพจนานุกรมด้วยพจนานุกรมอื่น

คุณสามารถเขียนส่วนขยายเพื่อทำ

var dict1 = ["a" : "foo"]
var dict2 = ["b" : "bar"]

extension Dictionary {
    mutating func update(other:Dictionary) {
        for (key,value) in other {
            self.updateValue(value, forKey:key)
        }
    }
}

dict1.update(dict2)
// dict1 is now ["a" : "foo", "b" : "bar]

3
นี่คือส่วนขยายที่ยอดเยี่ยมสำหรับพจนานุกรม!
Marc Attinasi

76

Swift 4ให้บริการmerging(_:uniquingKeysWith:)ดังนั้นสำหรับกรณีของคุณ:

let combinedDict = dict1.merging(dict2) { $1 }

การปิดชวเลขและการคืนสินค้า$1ดังนั้นค่าของ dict2 จะถูกใช้เมื่อมีข้อขัดแย้งกับกุญแจ


1
แค่อยากจะชี้ให้เห็นว่านี่เป็นบทสรุปที่กระชับและใกล้เคียงที่สุดที่ฉันได้พบกับเอกสารของ Apple ที่ระบุ- (void)addEntriesFromDictionary:(NSDictionary<KeyType, ObjectType> *)otherDictionary;ไว้ ในส่วนที่เกี่ยวกับสิ่งที่ซ้ำซ้อนจะระบุว่า: "หากพจนานุกรมทั้งสองมีคีย์เดียวกันวัตถุที่มีค่าก่อนหน้าของพจนานุกรมที่ได้รับสำหรับคีย์นั้นจะถูกส่งข้อความเผยแพร่และวัตถุค่าใหม่จะเข้าแทนที่ รุ่น Swift หรือในการผสาน (_: uniquingKeysWith :) ซึ่งส่งคืนค่าที่สอง$1เป็นสิ่งเดียวกับที่addEntriesFromDictionaryทำ
ทิมฟูกัว

31

มันไม่ได้สร้างไว้ในห้องสมุด Swift แต่คุณสามารถเพิ่มสิ่งที่คุณต้องการด้วยการใช้งานเกินกำลังเช่น:

func + <K,V>(left: Dictionary<K,V>, right: Dictionary<K,V>) 
    -> Dictionary<K,V> 
{
    var map = Dictionary<K,V>()
    for (k, v) in left {
        map[k] = v
    }
    for (k, v) in right {
        map[k] = v
    }
    return map
}

การ+ดำเนินการนี้เกินตัวดำเนินการสำหรับพจนานุกรมที่คุณสามารถใช้เพื่อเพิ่มพจนานุกรมด้วยตัว+ดำเนินการเช่น:

var dict1 = ["a" : "foo"]
var dict2 = ["b" : "bar"]

var dict3 = dict1 + dict2 // ["a": "foo", "b": "bar"]

1
คุณยังสามารถทำเพื่อ + = เพื่ออัปเดตแทน dict (ตามคำถาม op)
ร็อด

3
คุณสามารถทำได้ด้วยmapและปล่อยfor (k, v)...ลูปแรกถ้าคุณประกาศleftพารามิเตอร์เป็นvarและจากนั้นเพียงคัดลอกค่าจากrightลงในมัน
Nate Cook

2
@NateCook ที่จะทำให้กลายพันธุ์พจนานุกรมซึ่งไม่ได้คาดหวังพฤติกรรมสำหรับ+ตัวดำเนินการมัด
mythz

ขอบคุณสำหรับสิ่งนั้น คำตอบของคุณอาจแม่นยำยิ่งขึ้นสำหรับรหัสตัวอย่างที่ฉันโพสต์ในขณะที่อีกคำตอบหนึ่งคือสิ่งที่ฉันต้องการมากขึ้นตามคำถามของฉัน ไม่ดีของฉันแล้วให้ upvote ทั้งคุณ;)
สนิมเอง

2
@mythz มันไม่ได้กลายพันธุ์จริง ๆ เนื่องจาก+โอเปอเรเตอร์โอเวอร์โหลดไม่ใช่วิธีการอย่างใดอย่างหนึ่งDictionaryมันเป็นฟังก์ชั่นที่เรียบง่าย การเปลี่ยนแปลงที่คุณทำกับleftพารามิเตอร์ตัวแปรจะไม่สามารถมองเห็นได้นอกฟังก์ชั่น
Nate Cook

28

สวิฟท์ 3:

extension Dictionary {

    mutating func merge(with dictionary: Dictionary) {
        dictionary.forEach { updateValue($1, forKey: $0) }
    }

    func merged(with dictionary: Dictionary) -> Dictionary {
        var dict = self
        dict.merge(with: dictionary)
        return dict
    }
}

let a = ["a":"b"]
let b = ["1":"2"]
let c = a.merged(with: b)

print(c) //["a": "b", "1": "2"]

6
ดีขึ้นเล็กน้อยfunc merged(with dictionary: Dictionary<Key,Value>) -> Dictionary<Key,Value> { var copy = self dictionary.forEach { copy.updateValue($1, forKey: $0) } return copy }
Alexander Vasenin

16

Swift 2.0

extension Dictionary {

    mutating func unionInPlace(dictionary: Dictionary) {
        dictionary.forEach { self.updateValue($1, forKey: $0) }
    }

    func union(var dictionary: Dictionary) -> Dictionary {
        dictionary.unionInPlace(self)
        return dictionary
    }
}

ไม่สามารถเรียกใช้ฟังก์ชันการกลายพันธุ์จากฟังก์ชันที่ไม่กลายพันธุ์ได้เช่นนั้น
njzk2

unionฟังก์ชั่นที่มีค่าที่ส่งเข้ามาจะเป็นvarความหมายในพจนานุกรมคัดลอกที่สามารถกลายพันธุ์ มันค่อนข้างสะอาดกว่าfunc union(dictionary: Dictionary) -> Dictionary { var dict2 = dictionary; dict2.unionInPlace(self); return dict2 }ถ้ามีเพียงหนึ่งบรรทัด
MaddTheSane

2
params var จะเลิกใช้แล้วและจะถูกลบออกในสวิฟท์ 3. วิธีที่แนะนำการทำเช่นนี้อยู่ในขณะนี้ที่จะประกาศ var var dictionary = dictionaryในร่างกาย: จากที่นี่: github.com/apple/swift-evolution/blob/master/proposals/…
Daniel Wood

เพื่อเพิ่มความปลอดภัย<Key, Value>ให้กับประเภทของคุณให้เพิ่มสิ่งเหล่านั้นDictionaryลงไป
Raphael

12

ไม่เปลี่ยนรูป

ฉันชอบที่จะรวม / รวมพจนานุกรมที่ไม่เปลี่ยนรูปแบบเข้าด้วยกันกับ+โอเปอเรเตอร์ดังนั้นฉันจึงนำมาใช้เช่น:

// Swift 2
func + <K,V> (left: Dictionary<K,V>, right: Dictionary<K,V>?) -> Dictionary<K,V> {
    guard let right = right else { return left }
    return left.reduce(right) {
        var new = $0 as [K:V]
        new.updateValue($1.1, forKey: $1.0)
        return new
    }
}

let moreAttributes: [String:AnyObject] = ["Function":"authenticate"]
let attributes: [String:AnyObject] = ["File":"Auth.swift"]

attributes + moreAttributes + nil //["Function": "authenticate", "File": "Auth.swift"]    
attributes + moreAttributes //["Function": "authenticate", "File": "Auth.swift"]
attributes + nil //["File": "Auth.swift"]

ไม่แน่นอน

// Swift 2
func += <K,V> (inout left: Dictionary<K,V>, right: Dictionary<K,V>?) {
    guard let right = right else { return }
    right.forEach { key, value in
        left.updateValue(value, forKey: key)
    }
}

let moreAttributes: [String:AnyObject] = ["Function":"authenticate"]
var attributes: [String:AnyObject] = ["File":"Auth.swift"]

attributes += nil //["File": "Auth.swift"]
attributes += moreAttributes //["File": "Auth.swift", "Function": "authenticate"]

5
ฉันไม่เข้าใจว่าทำไมสิ่งนี้ถึงไม่ได้รับการสร้างขึ้นอย่างรวดเร็วโดยค่าเริ่มต้น
ioquatix

1
คุณตั้งใจค่าจากซ้ายไปแทนที่ขวาในโซลูชัน "ไม่เปลี่ยนรูป" ของคุณหรือไม่ ฉันคิดว่าคุณต้องมีright.reduce(left)อย่างน้อยนั่นก็เป็นพฤติกรรมที่คาดหวัง imo (และเป็นพฤติกรรมของตัวอย่างที่สองของคุณ) - เช่น ["A":1] + ["A":2]ควรส่งออก["A":2]
ccwasden

ผลลัพธ์สอดคล้องกับรหัส ฉันต้องการให้ค่าเริ่มต้นเป็นด้านขวาเหมือนตอนนี้
ricardopereira

12

ไม่จำเป็นต้องมีส่วนขยายพจนานุกรมใด ๆ เลย พจนานุกรม Swift (Xcode 9.0+) มีฟังก์ชันการทำงานนี้ ได้ดูที่นี่ ด้านล่างนี้เป็นตัวอย่างวิธีการใช้งาน

  var oldDictionary = ["a": 1, "b": 2]
  var newDictionary = ["a": 10000, "b": 10000, "c": 4]

  oldDictionary.merge(newDictionary) { (oldValue, newValue) -> Int in
        // This closure return what value to consider if repeated keys are found
        return newValue 
  }
  print(oldDictionary) // Prints ["b": 10000, "a": 10000, "c": 4]

2
ฉันกำลังเพิ่มสไตล์การใช้งานสำหรับตัวอย่างด้านบน:oldDictionary.merge(newDictionary) { $1 }
Andrej

11

ตัวแปรที่อ่านง่ายขึ้นโดยใช้ส่วนขยาย

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

3
ทางออกที่ดีมากและสะอาด!
user3441734

11

คุณสามารถลองสิ่งนี้

var dict1 = ["a" : "foo"]
var dict2 = ["b" : "bar"]

var temp = NSMutableDictionary(dictionary: dict1);
temp.addEntriesFromDictionary(dict2)

10

นอกจากนี้คุณยังสามารถใช้ลดเพื่อรวมพวกเขา ลองในสนามเด็กเล่น

let d1 = ["a":"foo","b":"bar"]
let d2 = ["c":"car","d":"door"]

let d3 = d1.reduce(d2) { (var d, p) in
   d[p.0] = p.1
   return d
}

สิ่งนี้ดูน่าสนใจ แต่มีอะไรdและp?
ปล้น

1
d คือผลลัพธ์ที่คงอยู่ของแต่ละรอบของการลดบล็อกและ p คือองค์ประกอบของคอลเลกชันที่จะถูกลดลง
farhadf

1
ดูเหมือนว่าจะมีปัญหาใน swift 3.0 beta
อยู่

พารามิเตอร์ var จะเลิกใช้ใน swift 3
Dmitry Klochkov

นี่คือทางออกที่ฉันโปรดปรานจากที่กล่าวถึงในที่นี้ ตัวกรอง / แผนที่ / ลดการชนะอีกครั้งสำหรับโซลูชันที่ยอดเยี่ยม
gokeji

7

ผมขอแนะนำให้ห้องสมุด SwifterSwift อย่างไรก็ตามหากคุณไม่ต้องการใช้ทั้งไลบรารีและส่วนเพิ่มเติมอื่น ๆ ทั้งหมดคุณสามารถใช้ประโยชน์จากส่วนขยายของพจนานุกรมได้:

Swift 3+

public extension Dictionary {
    public static func +=(lhs: inout [Key: Value], rhs: [Key: Value]) {
        rhs.forEach({ lhs[$0] = $1})
    }
}

ที่จริงแล้ว SE-110 ถูกเปลี่ยนกลับแล้วดังนั้น Swift 4 ควรเป็นเวอร์ชั่นเดียวกันกับ Swift 3
BallpointBen

5

คุณสามารถวนซ้ำชุดค่าคีย์ตามค่าที่คุณต้องการผสานและเพิ่มลงในเมธอด updateValue (forKey :):

dictionaryTwo.forEach {
    dictionaryOne.updateValue($1, forKey: $0)
}

ตอนนี้ค่าทั้งหมดของ dictionary ทั้งสองถูกเพิ่มเข้าไปใน dictionaryOne


4

เช่นเดียวกับคำตอบของ @ farhadf แต่ได้รับการรับรองสำหรับ Swift 3:

let sourceDict1 = [1: "one", 2: "two"]
let sourceDict2 = [3: "three", 4: "four"]

let result = sourceDict1.reduce(sourceDict2) { (partialResult , pair) in
    var partialResult = partialResult //without this line we could not modify the dictionary
    partialResult[pair.0] = pair.1
    return partialResult
}

4

Swift 3, ส่วนขยายพจนานุกรม:

public extension Dictionary {

    public static func +=(lhs: inout Dictionary, rhs: Dictionary) {
        for (k, v) in rhs {
            lhs[k] = v
        }
    }

}

4

ความคล่องตัวที่มากขึ้นสำหรับ Swift 4:

extension Dictionary {
    static func += (lhs: inout [Key:Value], rhs: [Key:Value]) {
        lhs.merge(rhs){$1}
    }
    static func + (lhs: [Key:Value], rhs: [Key:Value]) -> [Key:Value] {
        return lhs.merging(rhs){$1}
    }
}

3

คุณสามารถเพิ่มDictionaryส่วนขยายแบบนี้:

extension Dictionary {
    func mergedWith(otherDictionary: [Key: Value]) -> [Key: Value] {
        var mergedDict: [Key: Value] = [:]
        [self, otherDictionary].forEach { dict in
            for (key, value) in dict {
                mergedDict[key] = value
            }
        }
        return mergedDict
    }
}

จากนั้นใช้เป็นที่เรียบง่ายเป็นต่อไปนี้:

var dict1 = ["a" : "foo"]
var dict2 = ["b" : "bar"]

var combinedDict = dict1.mergedWith(dict2)
// => ["a": "foo", "b": "bar"]

หากคุณต้องการกรอบที่ยังมีบางคุณสมบัติที่มีประโยชน์มากขึ้นแล้วเช็คเอาท์HandySwift เพียงนำเข้าสู่โครงการของคุณและคุณสามารถใช้รหัสด้านบนโดยไม่ต้องเพิ่มส่วนขยายใด ๆในโครงการด้วยตัวคุณเอง


การติดตั้งห้องสมุดที่จะใช้ฟังก์ชั่นเดียวคือการปฏิบัติที่ไม่ดี
HackaZach

@HackaZach: ฉันเพิ่งปรับปรุงคำตอบของฉันเพื่อรวมส่วนที่เหมาะสมของกรอบการทำงานเพื่อป้องกันการรวมของห้องสมุดทั้งหมดหากต้องการเพียงส่วนเล็ก ๆ นี้ ฉันกำลังพูดถึงกรอบการทำงานสำหรับผู้ที่ต้องการใช้คุณลักษณะหลายอย่างของมัน ฉันหวังว่านี่จะช่วยให้ฝึกได้ดี!
Jeehut

3

ไม่จำเป็นต้องมีการขยายหรือ func พิเศษอีกต่อไป คุณสามารถเขียนเช่น:

firstDictionary.merge(secondDictionary) { (value1, value2) -> AnyObject in
        return object2 // what you want to return if keys same.
    }


1

คุณสามารถใช้ฟังก์ชัน bridgeToObjectiveC () เพื่อทำให้พจนานุกรมเป็น NSDictionary

จะเป็นดังนี้:

var dict1 = ["a":"Foo"]
var dict2 = ["b":"Boo"]

var combinedDict = dict1.bridgeToObjectiveC()
var mutiDict1 : NSMutableDictionary! = combinedDict.mutableCopy() as NSMutableDictionary

var combineDict2 = dict2.bridgeToObjectiveC()

var combine = mutiDict1.addEntriesFromDictionary(combineDict2)

จากนั้นคุณสามารถแปลง NSDictionary (รวม) กลับไปหรือทำอะไรก็ได้


ขออภัยคุณหมายถึงอะไรกันแน่?
Anton

เพียงแค่การตั้งค่า ดูเหมือนว่าจะเชื่อมโยงระหว่างภาษาที่ซับซ้อน ดีกว่าที่จะติดอยู่ในขอบเขตของภาษาเดียวในขณะที่ปล่อยให้ obj-c ตายเร็วกว่า
TruMan1

2
ใช่ฉันโพสต์คำตอบนี้อย่างแท้จริงในวันที่ประกาศอย่างรวดเร็ว ....... ดังนั้นจึงมีเหตุผล
Anton

1
import Foundation

let x = ["a":1]
let y = ["b":2]

let out = NSMutableDictionary(dictionary: x)
out.addEntriesFromDictionary(y)

ผลลัพธ์เป็น NSMutableDictionary ไม่ใช่พจนานุกรมพิมพ์ Swift แต่ไวยากรณ์ที่ใช้เหมือนกัน ( out["a"] == 1ในกรณีนี้) ดังนั้นคุณจะมีปัญหาเฉพาะเมื่อคุณใช้รหัสบุคคลที่สามซึ่งคาดว่าพจนานุกรม Swift หรือจริงๆ ต้องมีการตรวจสอบประเภท

คำตอบสั้น ๆ ที่นี่คือคุณต้องวนซ้ำ แม้ว่าคุณจะไม่ได้ป้อนมันอย่างชัดเจนนั่นคือสิ่งที่วิธีการที่คุณโทร (addEntriesFromDictionary: ที่นี่) จะทำ ฉันขอแนะนำว่าถ้าคุณยังไม่ชัดเจนว่าทำไมเป็นกรณีนี้คุณควรพิจารณาว่าคุณจะรวมโหนดใบไม้ของต้นไม้ B สองต้นได้อย่างไร

หากคุณต้องการประเภทพจนานุกรมดั้งเดิมของ Swift จริงๆแล้วฉันแนะนำ:

let x = ["a":1]
let y = ["b":2]

var out = x
for (k, v) in y {
    out[k] = v
}

ข้อเสียของวิธีการนี้คือดัชนีพจนานุกรม - แต่เสร็จแล้ว - อาจถูกสร้างใหม่หลายครั้งในการวนซ้ำดังนั้นในทางปฏิบัติสิ่งนี้ช้ากว่าวิธีการ NSMutableDictionary ประมาณ 10 เท่า


1

คำตอบทั้งหมดนี้ซับซ้อน นี่คือทางออกของฉันสำหรับ swift 2.2:

    //get first dictionnary
    let finalDictionnary : NSMutableDictionary = self.getBasicDict()
    //cast second dictionnary as [NSObject : AnyObject]
    let secondDictionnary : [NSObject : AnyObject] = self.getOtherDict() as [NSObject : AnyObject]
    //merge dictionnary into the first one
    finalDictionnary.addEntriesFromDictionary(secondDictionnary) 

สิ่งนี้ใช้ได้กับพจนานุกรมNSMutableDictionaryเท่านั้นและไม่ใช่พจนานุกรมของ Swift ดั้งเดิม ฉันหวังว่าสิ่งนี้จะถูกเพิ่มไปยัง Swift อย่างเป็นทางการ
Chris Paveglio

0

ความต้องการของฉันแตกต่างกันฉันต้องรวมชุดข้อมูลที่ซ้อนกันไม่สมบูรณ์โดยไม่ต้องปิดบัง

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

0

สวิฟท์ 2.2

func + <K,V>(left: [K : V], right: [K : V]) -> [K : V] {
    var result = [K:V]()

    for (key,value) in left {
        result[key] = value
    }

    for (key,value) in right {
        result[key] = value
    }
    return result
}

หากคุณวางสิ่งนี้ไว้คุณสามารถลบลูปแรกได้: `var result = left`
NikeAlive

0

ฉันจะใช้ห้องสมุดดอลลาร์

https://github.com/ankurp/Dollar/#merge---merge-1

ผสานพจนานุกรมทั้งหมดเข้าด้วยกันและพจนานุกรมหลังจะแทนที่ค่าที่คีย์ที่กำหนด

let dict: Dictionary<String, Int> = ["Dog": 1, "Cat": 2]
let dict2: Dictionary<String, Int> = ["Cow": 3]
let dict3: Dictionary<String, Int> = ["Sheep": 4]
$.merge(dict, dict2, dict3)
=> ["Dog": 1, "Cat": 2, "Cow": 3, "Sheep": 4]

5
jQuery กลับมาแล้ว!
เบ็นซินแคลร์

0

นี่คือส่วนขยายที่ดีที่ฉันเขียน ...

extension Dictionary where Value: Any {
    public func mergeOnto(target: [Key: Value]?) -> [Key: Value] {
        guard let target = target else { return self }
        return self.merging(target) { current, _ in current }
    }
}

ใช้:

var dict1 = ["cat": 5, "dog": 6]
var dict2 = ["dog": 9, "rodent": 10]

dict1 = dict1.mergeOnto(target: dict2)

จากนั้น dict1 จะถูกแก้ไขเป็น

["cat": 5, "dog": 6, "rodent": 10]
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.