如何检查两个[String:Any]是否相同?

时间:2016-08-26 11:12:18

标签: swift swift3

有没有办法检查两个[String:Any]是否相同?

let actual: [[String: Any]] = [
    ["id": 12345, "name": "Rahul Katariya"],
    ["id": 12346, "name": "Aar Kay"]
]
var expected: [[String: Any]]!

if actual == expected {
    print("Equal")
}

基本上我希望Dictionary符合Swift 3中的Equatable协议。

3 个答案:

答案 0 :(得分:13)

对于 Xcode 7.3,swift 2.2 字典的类型为:[String:AnyObject]或简单地放入NSDictionary

let actual: [String: AnyObject] = ["id": 12345, "name": "Rahul Katariya"]


var expected: [String: AnyObject] = ["id": 12346, "name": "Aar Kay"]


print(NSDictionary(dictionary: actual).isEqualToDictionary(expected))//False

对于 Xcode 8.beta 6,Swift 3

字典定义为:

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

NSDictionary具有以下便利初始化程序:

convenience init(dictionary otherDictionary: [AnyHashable : Any])

因此,您可以将AnyHashable类型用于Key,将任意类型用于Value

let actual: [String: Any] = ["id": 12345, "name": "Rahul Katariya"]

var expected: [String: Any] = ["id": 12346, "name": "Aar Kay"]


print(NSDictionary(dictionary: actual).isEqual(to: expected))//False

答案 1 :(得分:3)

Swift中的Any类型不是Equatable,因此包括Any在内的任何集合类型都不能是Equatable

您可以在Swift 3 / Xcode 8 beta 6中编写类似的内容:

if actual as NSArray == expected as NSArray {
    print("Equal")
}

但是,由于导入idAny 刚刚在测试版6中引入,所以此行为可能会在不久的将来发生变化。

答案 2 :(得分:3)

Equatable外;对于练习,您可以编写自己的isEqual函数来比较两个[T: Any]字典,以获取您知道{Equatable包含的值的子集。 {1}}仅限于。通过尝试转换为这些类型(例如,在Any语句中,如下所示),您可以在转换为这些给定类型之后逐个比较字典的值(对于每个给定的键) 。 E.g。

switch

用法:

// Usable if the 'Any' values in your dict only wraps
// a few different types _that are known to you_.
// Return false also in case value cannot be successfully 
// converted to some known type. This might yield a false negative.
extension Dictionary where Value: Any {
    func isEqual(to otherDict: [Key: Any], 
                 allPossibleValueTypesAreKnown: Bool = false) -> Bool {
        guard allPossibleValueTypesAreKnown && 
            self.count == otherDict.count else { return false }
        for (k1,v1) in self {
            guard let v2 = otherDict[k1] else { return false }
            switch (v1, v2) {
                case (let v1 as Double, let v2 as Double) : if !(v1.isEqual(to: v2)) { return false }
                case (let v1 as Int, let v2 as Int) : if !(v1==v2) { return false } 
                case (let v1 as String, let v2 as String): if !(v1==v2) { return false }
                // ... fill in with types that are known to you to be 
                // wrapped by the 'Any' in the dictionaries
                default: return false
            }
        }
    return true
    } 
}

请注意/* example setup */ var dict1: [String: Any] = ["id": 12345, "name": "Rahul Katariya", "weight": 70.7] var dict2: [String: Any] = ["id": 12346, "name": "Aar Kay", "weight": 83.1] /* example usage */ print(dict1.isEqual(to: dict2, allPossibleValueTypesAreKnown: true)) // false dict2["name"] = "Rahul Katariya" dict2["weight"] = 70.7 print(dict1.isEqual(to: dict2, allPossibleValueTypesAreKnown: true)) // false dict2["id"] = 12345 print(dict1.isEqual(to: dict2, allPossibleValueTypesAreKnown: true)) // true class Foo {} dict1["id"] = Foo() dict2["id"] = Foo() print(dict1.isEqual(to: dict2, allPossibleValueTypesAreKnown: true)) // false! (we haven't implemented this attempted conversion!) // incompatable keys cause error as expected an intended let dict3: [Int: Any] = [1:2] dict1.isEqual(to: dict3) /* error: cannot convert value of type '[Int : Any]' to expected argument type '[String : Any]' */ 转换可能产生误报(as)的危险,因为它可以允许从两种不同类型映射到另一种常见类型,例如在将两个派生类实例转换为它们的公共父类型时,将派生类差异切除:

true

如果您更喜欢失败的“已知类型转换”返回class Base: Equatable {} func ==(lhs: Base, rhs: Base) -> Bool { return true } class DerivedA : Base { let foo = "foo" } class DerivedB : Base { let bar = 4.2 } let a = DerivedA() let b = DerivedB() switch (a, b) { case (let a as Base, let b as Base): print(a == b) default: () } // sliced by conversion! prints "true" (而成功的转化将始终产生nil / true,基于后续的相等测试),您可以将上述内容扩展到(甚至更加混乱)

false

但请注意,在// a 'nil' return here would correspond to an invalid call extension Dictionary where Value: Any { func isEqual(to otherDict: [Key: Any], allPossibleValueTypesAreKnown: Bool = false) -> Bool? { guard allPossibleValueTypesAreKnown else { return nil } guard self.count == otherDict.count else { return false } for (k1,v1) in self { guard let v2 = otherDict[k1] else { return false } switch (v1, v2) { case (let v1 as Double, let v2 as Double) : if !(v1.isEqual(to: v2)) { return false } case (let v1 as Int, let v2 as Int) : if !(v1==v2) { return false } case (let v1 as String, let v2 as String): if !(v1==v2) { return false } // ... case (_ as Double, let v2): if !(v2 is Double) { return false } case (_, _ as Double): return false case (_ as Int, let v2): if !(v2 is Int) { return false } case (_, _ as Int): return false case (_ as String, let v2): if !(v2 is String) { return false } case (_, _ as String): return false default: return nil } } return true } } /* Example as per above will yield (printout): Optional(false) Optional(false) Optional(true) nil */ 命中的情况下,上面的值相等测试值会被短路,这意味着根据非有序字典的随机顺序(非有序集合),鉴于两个不相等的词典,特殊情况可能会返回false以及nil。这种特殊情况发生在两个非等值的字典(已知类型值 - 值对的不相等)中,它还包含未包含在尝试的转换中的值类型:如果首先命中已知类型的不相等,将返回false,而如果首先点击失败的转化,则会返回false。无论哪种方式,nil返回意味着该调用应被视为无效,因为调用方声明nilallPossibleValueTypesAreKnown(转换失败意味着true)。