比较字典时排除特定键

3

我有两个字典:

let foo: [String: Any] = ["name": "John", "isHuman": true, "age": 20]
let bar: [String: Any] = ["name": "Ann", "isHuman": true, "age": 34]

我希望能够进行比较,同时从比较中排除某些关键字。我想要排除的关键字在另一个字典中:

let car: [String: Any] = ["age": 20]

我有这个扩展:

extension Dictionary where Key: Equatable {
    func isEqualTo(_ dictionary: Dictionary, excluding: [Key] = []) -> Bool {
      let left = filter({ !excluding.contains($0.key) })
      let right = dictionary.filter({ !excluding.contains($0.key) })
      return NSDictionary(dictionary: left).isEqual(to: right)
    }
}

但是当我调用它时,我需要将排除的键包装在Array中,否则编译器会报错:

无法将类型为“Dictionary.Keys”的值转换为预期的参数类型“[String]”

foo.isEqualTo(bar, excluding: Array(car.keys))可以工作。

foo.isEqualTo(bar, excluding: car.keys)会导致编译器错误。

我能否调整我的扩展程序以避免将排除的键包装在Array中?


1
func isEqualTo(_ dictionary: Dictionary, excluding: Dictionary.Keys) -> Bool 这个怎么样? - Alladinian
2个回答

4

car.keys的类型是Dictionary<Key, Value>.Keys,它是一个集合而不是数组。

如果您将函数声明为

func isEqualTo<C: Collection>(_ dictionary: Dictionary, excluding: C) -> Bool
        where C.Element == Key

然后两者皆是。
foo.isEqualTo(bar, excluding: Array(car.keys))
foo.isEqualTo(bar, excluding: car.keys)

编译并工作。

这样做的额外好处是可以传入一个普通的字符串数组,非常不错。但是如何更新代码以使excluding具有与原始值相同的默认值呢? - rmaddy
@maddy 我更新了它为 wmf_isEqualTo<C: Collection>(_ dictionary: Dictionary, excluding excludedKeys: C? = nil) -> Bool where C.Element == Key 并防止 excludedKeys 为空,如果是这种情况则返回 NSDictionary(dictionary: self).isEqual(to: dictionary) - nambatee
是的,excludedKeys: C? = nil 是我即将建议的。 - Martin R
还有一个 EmptyCollection 类型,但是 excluding: C = EmptyCollection<Key>() 无法编译... - Martin R

2

excluding 声明为类型 Keys

func isEqualTo(_ dictionary: Dictionary, excluding: Keys = [:].keys) -> Bool {

顺便提一下,你可以通过更新你的代码来消除对NSDictionary的使用:

let foo: [String: AnyHashable] = ["name": "John", "isHuman": true, "age": 20]
let bar: [String: AnyHashable] = ["name": "Ann", "isHuman": true, "age": 34]

let car: [String: Any] = ["age": 20, "name":"Bob"]

extension Dictionary where Key: Equatable, Value: Equatable {
    func isEqualTo(_ dictionary: Dictionary, excluding: Keys = [:].keys) -> Bool {
        let left = filter({ !excluding.contains($0.key) })
        let right = dictionary.filter({ !excluding.contains($0.key) })
        return left == right
    }
}

注意在字典中使用AnyHashable而不是Any,并注意在扩展中添加了, Value: Equatable


我曾尝试过使用 Value: Equatable,但没有想到使用 AnyHashable。这比使用 NSDictionary 更好。 - Martin R
[:].keys 哎呀,我知道它的含义和为什么它是有效的,但那真的看起来像是滥用语法 :p - Alexander
@Alexander,我很想知道创建一个空的Keys实例的更好方法。 - rmaddy
@rmaddy 你可以这样写:Dictionary().keys。不确定这是否更好,但对于未接触过的人来说,它会稍微简单一些。 - Alexander

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接