Compare arrays in swift Compare arrays in swift arrays arrays

Compare arrays in swift


You’re right to be slightly nervous about ==:

struct NeverEqual: Equatable { }func ==(lhs: NeverEqual, rhs: NeverEqual)->Bool { return false }let x = [NeverEqual()]var y = xx == y  // this returns true[NeverEqual()] == [NeverEqual()] // falsex == [NeverEqual()] // falselet z = [NeverEqual()]x == z // falsex == y // truey[0] = NeverEqual()x == y // now false

Why? Swift arrays do not conform to Equatable, but they do have an == operator, defined in the standard library as:

func ==<T : Equatable>(lhs: [T], rhs: [T]) -> Bool

This operator loops over the elements in lhs and rhs, comparing the values at each position. It does not do a bitwise compare – it calls the == operator on each pair of elements. That means if you write a custom == for your element, it’ll get called.

But it contains an optimization – if the underlying buffers for the two arrays are the same, it doesn’t bother, it just returns true (they contain identical elements, of course they’re equal!).

This issue is entirely the fault of the NeverEqual equality operator. Equality should be transitive, symmetric and reflexive, and this one isn't reflexive (x == x is false). But it could still catch you unawares.

Swift arrays are copy-on-write – so when you write var x = y it doesn’t actually make a copy of the array, it just points x’s storage buffer pointer at y’s. Only if x or y are mutated later does it then make a copy of the buffer, so that the unchanged variable is unaffected. This is critical for arrays to behave like value types but still be performant.

In early versions of Swift, you actually could call === on arrays (also in early versions, the mutating behaviour was a bit different, if you mutated x, y would also change even though it had been declared with let – which freaked people out so they changed it).

You can kinda reproduce the old behaviour of === on arrays with this (very implementation-dependent not to be relied-on except for poking and prodding investigations) trick:

let a = [1,2,3]var b = aa.withUnsafeBufferPointer { outer in     b.withUnsafeBufferPointer { inner in         println(inner.baseAddress == outer.baseAddress)     } }


== in Swift is the same as Java's equals(), it compares values.

=== in Swift is the same as Java's ==, it compares references.

In Swift you can compare array content values as easy as this:

["1", "2"] == ["1", "2"]

But this will not work if you want to compare references:

var myArray1 = [NSString(string: "1")]var myArray2 = [NSString(string: "1")]myArray1[0] === myArray2[0] // falsemyArray1[0] == myArray2[0] // true

So the answers:

  1. I think the performance is optimal for doing value (not reference)comparisons
  2. Yes, if you want to compare values
  3. Swift arrays are value type and not reference type. So the memorylocation is the same only if you compare it to itself (or use unsafepointers)


It depends on how do you want to compare. For example:["1", "2"] == ["1", "2"] // truebut["1", "2"] == ["2", "1"] // false

If you need that second case to also be true and are ok with ignoring repetitive values, you can do:Set(["1", "2"]) == Set(["2", "1"]) // true(use NSSet for Swift 2)