有没有办法检查两个[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协议。
答案 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")
}
但是,由于导入id
为Any
刚刚在测试版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
返回意味着该调用应被视为无效,因为调用方声明nil
为allPossibleValueTypesAreKnown
(转换失败意味着true
)。