gpt4 book ai didi

swift - 合并两个字典的通用函数

转载 作者:可可西里 更新时间:2023-11-01 00:59:18 27 4
gpt4 key购买 nike

我想要一个通用函数来合并两个词典。它需要比 How do you add a Dictionary of items into another Dictionary 中描述的更通用.原因:我的字典中有对象,我只想更新特定属性而不是整个对象本身。 (具体来说,它们是具有数组属性的对象。如果对象存在,我需要附加到这个数组,或者用新数组创建一个新对象。我不能简单地检查并相应地覆盖整个对象。我'我对它的属性很感兴趣。)

我尝试使用函数式编程来做到这一点:

extension Dictionary {
func merge(withDictionary: Dictionary) -> Dictionary {
var returnDictionary = withDictionary // make a copy of dictionary (a dictionary is a struct in Swift)
// Merge self dictionary into returnDictionary
for key in self.keys {
// If there is already a value associated for this key. (In my concrete case I will need to append to the value object's list property.)
if let withDictionaryValue = returnDictionary[key], selfValue = self[key] {

// I NEED TO DO THIS HERE.
//
// returnDictionary[key]!.list = withDictionaryValue.list + selfValue.list
//
// CAN'T FIGURE OUT HOW TO DO THIS IN A GENERIC WAY. THIS GENERIC MERGE SHOULDN'T NEED TO KNOW THAT THIS PARTICULAR DICTIONARY HAS VALUE OBJECTS THAT CONTAIN A 'list' PROPERTY.
// HOW DO I PASS THIS CODE SNIPPET LINE IN AS PART OF A CLOSURE, WHICH USES 'withDictionaryValue' AND 'selfValue'?

} else {
// Simply write into this key - it doesn't yet contain values.
returnDictionary[key] = self[key]
}
}

return returnDictionary

}

}

最佳答案

This generic merge shouldn't need to know that this particular dictionary has value objects that contain a 'list' property.

相反,为了让您的函数访问字典值的 list 属性,您需要告诉编译器这些值具有 list 属性。您可以通过创建一个协议(protocol)并将扩展限制为仅对具有符合该协议(protocol)的值的字典进行操作来做到这一点:

// your protocol that defines the list property
protocol ListType {
var list : [AnyObject] { get set }
}

extension Dictionary where Value : ListType {
func merge(withDictionary: Dictionary) -> Dictionary {
var returnDictionary = withDictionary // make a copy of dictionary (a dictionary is a struct in Swift)

for (key, value) in self { // iterate through key value pairs
if let withDictionaryValue = returnDictionary[key] { // if value exists, merge the list properties
returnDictionary[key]!.list = value.list + withDictionaryValue.list
} else {
returnDictionary[key] = value
}
}
return returnDictionary
}
}

然后您可以直接或通过扩展使您正在使用的值类型符合此协议(protocol)。

struct Foo : ListType {
var list: [AnyObject]
}

let d = ["foo" : Foo(list: ["foo", "bar", "baz"])]
let d1 = ["foo" : Foo(list: ["qux", "blah", "blue"])]

let r = d.merge(d1) // ["foo": Foo(list: [foo, bar, baz, qux, blah, blue])]

如果您想要一种更通用的方法,您可以定义一个 Mergable 协议(protocol),该协议(protocol)定义一种方法,在该方法中,符合类型可以执行自己的合并逻辑。然后,如果值符合协议(protocol),您将更改您的扩展以调用此方法,否则只需合并键值对。

protocol Mergable {
func merge(withOther:Self) -> Self
}

// if values are Mergable (and the key-value pairs exist in both dictionaries), then call their custom logic for merging
extension Dictionary where Value : Mergable {
func merge(withDictionary: Dictionary) -> Dictionary {
var returnDictionary = withDictionary
for (key, value) in self {
if let withDictionaryValue = withDictionary[key] {
returnDictionary[key] = value.merge(withDictionaryValue)
} else {
returnDictionary[key] = value
}
}
return returnDictionary
}
}

// standard merging logic
extension Dictionary {
func merge(withDictionary: Dictionary) -> Dictionary {
var returnDictionary = withDictionary
keys.forEach {returnDictionary[$0] = self[$0]}
return returnDictionary
}
}

然后您可以像这样使您的值类型符合此协议(protocol):

// Foo's custom merging logic
extension Foo : Mergable {
func merge(withOther: Foo) -> Foo {
var merged = self

// merge the list array
merged.list.appendContentsOf(withOther.list)

return merged
}
}

如果您的字典的值是Mergable,那么编译器将支持执行自定义合并逻辑的扩展,因为首选更特定于类型的签名。


在回复您关于希望使用闭包执行此操作的评论时,您可以merge 函数添加一个闭包参数,该函数将传递对第一个值的伪引用(通过使用 inout)和第二个值,允许您在调用函数时改变第一个值。

extension Dictionary {
func merge(withDictionary: Dictionary, @noescape merge: (value: inout Value, withValue: Value) -> ()) -> Dictionary {
var returnDictionary = withDictionary // make a copy of dictionary (a dictionary is a struct in Swift)

for (key, value) in self { // iterate through key value pairs
if let withDictionaryValue = returnDictionary[key] {

// create mutable copy of the value
var value = value
merge(value:&value, withValue:withDictionaryValue) // invoke closure to write merging changes to the value
returnDictionary[key] = value // assign value

} else {
returnDictionary[key] = value
}
}
return returnDictionary
}
}

// call merge with our own custom merging logic when a given key exists in both dictionaries
let result = dictA.merge(dictB) {$0.list.appendContentsOf($1.list)}

虽然这只有在您每次调用该函数时合并逻辑都发生变化时才真正有意义,但我怀疑这不是您正在做的。

如果您希望您的合并逻辑保持不变,那么最好使用协议(protocol)来完成。使用闭包,每次调用函数时都必须传入合并逻辑。使用协议(protocol),您只需定义一次该逻辑,然后在需要时调用它。

关于swift - 合并两个字典的通用函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37741027/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com