Swift equality operator on nested arrays
Why does the last statement fail to compile with the error: Binary operator '==' cannot be applied to two '[[Simple]]’ operands
, and is there a way way to modify the Simple
struct or extend the ==
operator to be able to perform equality checks on nested arrays (or dictionaries)?
var i1: [Int] = [1]
var i2: [Int] = [1]
i1 == i2 // -> true
var i3: [[Int]] = [[1], [2]]
var i4: [[Int]] = [[1], [2]]
i3 == i4 // -> true
struct Simple: Equatable, Hashable {
let message: String
var hashValue: Int {
return message.hashValue
}
}
func ==(lhs: Simple, rhs: Simple) -> Bool {
return lhs.message == rhs.message
}
var a: [Simple] = [Simple(message: "a")]
var b: [Simple] = [Simple(message: "a")]
a == b // -> true
var x: [[Simple]] = [[Simple(message: "a")], [Simple(message: "b")]]
var y: [[Simple]] = [[Simple(message: "a")], [Simple(message: "b")]]
x == y // -> ERROR! Binary operator '==' cannot be applied to two '[[Simple]]’ operands
Update: Conditional conformance has been implemented in Swift 4.1. In particular:
The standard library types Optional, Array, and Dictionary now conform to the Equatable protocol when their element types conform to Equatable. ...
(from the Swift CHANGELOG).
Arbitrarily nested arrays of Equatable
elements are Equatable
now
and can be compared with ==
. Your code
var x: [[Simple]] = [[Simple(message: "a")], [Simple(message: "b")]]
var y: [[Simple]] = [[Simple(message: "a")], [Simple(message: "b")]]
x == y
compiles in Xcode 9.3 if Simple
is Equatable
.
(Old answer:)
The reason is similar as in Why is Equatable not defined for optional arrays. Arrays can be compared with ==
if the element type is Equatable
:
/// Returns true if these arrays contain the same elements.
public func ==<Element : Equatable>(lhs: [Element], rhs: [Element]) -> Bool
That's why
var a: [Simple] = [Simple(message: "a")]
var b: [Simple] = [Simple(message: "a")]
a == b // -> true
compiles.
But even for equatable types T
, Array<T>
does not conform to the Equatable
protocol, compare Why can't I make Array conform to Equatable?. Therefore, in
var x: [[Simple]] = [[Simple(message: "a")], [Simple(message: "b")]]
var y: [[Simple]] = [[Simple(message: "a")], [Simple(message: "b")]]
x == y // -> ERROR! Binary operator '==' cannot be applied to two '[[Simple]]’ operands
x
and y
are arrays with the element type [Simple]
which does
not conform to the Equatable
protocol, and there is no
matching ==
operator.
You could define a generic ==
operator for simply nested arrays as
func ==<Element : Equatable> (lhs: [[Element]], rhs: [[Element]]) -> Bool {
return lhs.count == rhs.count && !zip(lhs, rhs).contains {$0 != $1 }
}
or more simply (as suggested by @kennytm):
func ==<Element : Equatable> (lhs: [[Element]], rhs: [[Element]]) -> Bool {
return lhs.elementsEqual(rhs, by: ==)
}
This makes x == y
compile and work as expected. At present, there seems
to be no way to define a ==
operator on arbitrarily nested arrays.
You can do it by implementing a ==
function for it, like following:
func == (lhs: [[Simple]], rhs: [[Simple]]) -> Bool {
//your code
}