如何在Swift中比较两个字典?


69

是否有一种简便的方法可以[String: AnyObject]快速比较两个字典,因为它不接受==运算符?

通过比较两个字典,我的意思是检查它们是否具有相同的精确键,并且对于每个键都具有相同的值。

Answers:


120

正如Hot Licks所述,您可以使用NSDictionary方法isEqualToDictionary()来检查它们是否相等,如下所示:

let dic1: [String: AnyObject] = ["key1": 100, "key2": 200]
let dic2: [String: AnyObject] = ["key1": 100, "key2": 200]
let dic3: [String: AnyObject] = ["key1": 100, "key2": 250]

println( NSDictionary(dictionary: dic1).isEqualToDictionary(dic2) )   // true
println( NSDictionary(dictionary: dic1).isEqualToDictionary(dic3) )  // false

您还可以实现自定义运算符“ ==”,如下所示:

public func ==(lhs: [String: AnyObject], rhs: [String: AnyObject] ) -> Bool {
    return NSDictionary(dictionary: lhs).isEqualToDictionary(rhs)
}

println(dic1 == dic2)   // true
println(dic1 == dic3)   // false

Xcode 9•Swift 4

从文档开始,字典现在被定义为一个结构:

struct Dictionary<Key : Hashable, Value> : Collection, ExpressibleByDictionaryLiteral

描述

一个集合,其元素为键值对。字典是一种哈希表,可以快速访问它所包含的条目。表中的每个条目都使用其键来标识,该键是可哈希的类型,例如字符串或数字。您可以使用该键检索相应的值,该值可以是任何对象。在其他语言中,类似的数据类型称为哈希或关联的数组。通过使用字典文字来创建新字典。字典文字是键值对的逗号分隔列表,其中冒号将每个键与其关联的值分开,并用方括号括起来。您可以将字典文字分配给变量或常量,也可以将其传递给需要字典的函数。

这是创建HTTP响应代码及其相关消息的字典的方法:

var responseMessages = [200: "OK",
                        403: "Access forbidden",
                        404: "File not found",
                        500: "Internal server error"]

推断responseMessages变量具有type [Int: String]。字典的键类型是,字典Int的值类型是String

要创建没有键值对的字典,请使用空的字典文字([:])。

var emptyDict: [String: String] = [:]

任何符合Hashable协议的类型都可以用作字典的Key类型,包括Swift的所有基本类型。通过使它们符合哈希协议,可以将自己的自定义类型用作字典键。


我们不再需要定义自定义运算符:

从文档:

static func ==(lhs: [Key : Value], rhs: [Key : Value]) -> Bool

测试:

let dic1 = ["key1": 100, "key2": 200]
let dic2 = ["key1": 100, "key2": 200]
let dic3 = ["key1": 100, "key2": 250]

print(dic1 == dic2)   // true
print(dic1 == dic3)   // false

在上面的示例中,所有字典键和值都是相同的类型。如果我们尝试比较两个[String: Any]Xcode类型的字典,则会抱怨Binary运算符==不能应用于两个[String: Any]操作数。

let dic4: [String: Any] = ["key1": 100, "key2": "200"]
let dic5: [String: Any] = ["key1": 100, "key2": "200"]
let dic6: [String: Any] = ["key1": 100, "key2": Date()]

print(dic4 == dic5)  // Binary operator == cannot be applied to two `[String: Any]` operands

但是我们可以扩展==操作程序功能,实现一个中缀运算符,将Swift字典转换为NSDictionary并将字典值限制为Hashable Protocol:


Xcode 11•Swift 5.1

public func ==<K, L: Hashable, R: Hashable>(lhs: [K: L], rhs: [K: R] ) -> Bool {
   (lhs as NSDictionary).isEqual(to: rhs)
}

测试:

let dic4: [String: AnyHashable] = ["key1": 100, "key2": "200"]
let dic5: [String: AnyHashable] = ["key1": 100, "key2": "200"]
let dic6: [String: AnyHashable] = ["key1": 100, "key2": Date()]

print(dic4 == dic5)   // true
print(dic4 == dic6)   // false

let dic7: [String: String] = [ "key2": "200"]
let dic8: [String: Date] = [ "key2": Date()]
print(dic7 == dic8)   // false

1
这看起来像是使用类型约束的通用协议的最佳候选者。
AnBisw

15

Swift 4更新:

比较字典现在是本地的!(此处的文档)


斯威夫特3:

Leo Dabus已经写了一篇出色的文章,介绍了接受的解决方案。但是,对我而言,我发现它还需要一步来完全可用。从他的代码可以看到,您需要将字典类型设置为[AnyHashable: Any],否则您将得到Binary operator '==' cannot be applied to two '[String : Any]' operands,以在我的示例中使用反序列化JSON中常见的字典。

通用救援!:

// Swift 3.0
func == <K, V>(left: [K:V], right: [K:V]) -> Bool {
    return NSDictionary(dictionary: left).isEqual(to: right)
}

或者在另一种情况下,我有[String: Any?]

func == <K, V>(left: [K:V?], right: [K:V?]) -> Bool {
    guard let left = left as? [K: V], let right = right as? [K: V] else { return false }
    return NSDictionary(dictionary: left).isEqual(to: right)
}

我在哪里定义此方法?
Avinash Sharma,

这可以在任何地方完成,因此我通常将其放在单独的文件中,通常类似Foundation+utils.swift或类似的东西。从Xcode 10.2开始,不支持KIM,Swift 3,因此您很可能将不再需要此功能。:bittersweet情绪:;)
AmitaiB

11

在斯威夫特2,当这两个KeyValueEquatable,你可以使用==的字典本身:

public func ==<Key : Equatable, Value : Equatable>(lhs: [Key : Value], rhs: [Key : Value]) -> Bool

而且,NSObject是可等于的:

public func ==(lhs: NSObject, rhs: NSObject) -> Bool

在您的情况下,如果您要使用进行比较的Obj-C对象,则isEqual:可以简单地使用NSObject作为值类型(而不是AnyObject)。


不幸的是,我没有使用
Swift

3
您很快就会成为现实,几天之内即将发布iOS9。
zaph

0

在没有自定义类型的Dictionary值的情况下,在Swift 2+中,您可以使用==运算符比较两个Dictionary以检查它们是否相等。

但是在某些情况下,自定义类型为Dictionary的值(如struct),必须采用Equatable该类型才能使该自定义类型使用==运算符。

例如:

// custom type
struct Custom: Equatable {
    var value: Int
}

// MARK: adopting Equatable
func ==(lhs: Custom, rhs: Custom) -> Bool {
    if lhs.value == rhs.value {
        return true
    } else {
        return false
    }
}

现在,您可以使用==运算符比较两个字典:

let dic3: [String: Custom] = ["key1": Custom(value:1), "key2": Custom(value:2)]
let dic4: [String: Custom] = ["key1": Custom(value:1), "key2": Custom(value:2)]

if (dic3 == dic4) {
    print("equal")
} else {
    print("not equal")
}

你为什么不写func == <Key: Equatable, Value: Equatable>(lhs: [Key, Value], rhs: [Key, Value])
NoodleOfDeath '16

字典的@NoodleofDeath值不是Equatable类型。我想在Swift中编写函数,该函数不依赖于可可库类型(如NSObject,NSDictionary)
幼虫
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.