Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to test equality of Swift arrays of named tuples

Tags:

swift

Swift tuples are not Equatable, and as compound types, they can't be made Equatable through protocol extension. The workaround (as documented in another answer) is to create an overload for the == operator for each arity of tuples.

Interestingly, one can declare the == operator for regular tuples and use it to compare tuples with named fields:

func ==<T1: Equatable, T2: Equatable>(lhs: (T1,T2), rhs: (T1,T2)) -> Bool {
    return lhs.0 == rhs.0 && lhs.1 == rhs.1
}

var one = ("One", 1)
let two = ("Two", 2)
print(one == two) // "false"

typealias NamedTuple2 = (name: String, value: Int)
var namedone: NamedTuple2 = (name: "One", value: 1)
let namedtwo: NamedTuple2 = (name: "Two", value: 2)
print(namedone == namedtwo) // "false"
print(namedone == one) // "true"

Arrays of tuples also need a custom overload to be compared as a whole:

func ==<T0: Equatable, T1: Equatable>(lhs: [(T0, T1)], rhs: [(T0, T1)]) -> Bool {
    if lhs.count != rhs.count {
        return false
    }
    for (index, value) in lhs.enumerate() {
        if !(value == rhs[index]) {
            return false
        }
    }
    return true
}

let array12: [(String, Int)] = [one, two]
let array3: [Tuple2] = [("Three", 3)]
print(array12 == array3) // "false"

However, this operator doesn't accept an array of named tuples:

let namedarray12: [NamedTuple2] = [namedone, namedtwo]
let namedarray3: [NamedTuple2] = [array3[0]]
print(namedarray12 == namedarray3)
// error: binary operator '==' cannot be applied to two '[NamedTuple2]' operands

Is there a way to test equality of arrays of named tuple, without declaring an overload of == for the particular named tuple?

like image 369
Jay Lieske Avatar asked Sep 28 '15 01:09

Jay Lieske


People also ask

How to compare tuples in Swift?

To compare tuples, just use the == operator, like this: let singer = ("Taylor", "Swift") let alien = ("Justin", "Bieber") if singer == alien { print("Matching tuples!") } else { print("Non-matching tuples!") }

Can we compare two tuples in Swift?

Suggested approach: Swift provides automatic tuple comparison ever since Swift 2.2 – you can just use == to compare tuples item by item. For bonus points you could mention that tuple comparison does not guarantee that both tuples use the same element names.

Are Swift tuples Equatable?

The rule is simple: if all of the tuple elements are themselves Equatable then the overall tuple itself conforms to Equatable . It's also important to note that this conformance does not take into account the tuple labels in consideration for equality.

What is difference between tuple and array in Swift?

Tuple A tuple is a grouping of unnamed, ordered values. Each value in a tuple does not need to be the same type. Array An array is mutable collection. They are very efficient to create, but must always be a single type.


1 Answers

The method SequenceType.elementsEqual(_,isEquivalent:) accepts a predicate for comparing elements. The same == overload works for both named and unnamed tuples. So instead of trying to apply == to the arrays as a whole, use elementsEqual.

func ==<T1: Equatable, T2: Equatable>(lhs: (T1,T2), rhs: (T1,T2)) -> Bool {
    return lhs.0 == rhs.0 && lhs.1 == rhs.1
}

let namedarray: [(name: String, value: Int)] = [(name: "One", value: 1), (name: "Two", value: 2)]
// namedarray == namedarray12
namedarray.elementsEqual(namedarray12, isEquivalent: ==) // true
like image 71
Jay Lieske Avatar answered Sep 22 '22 02:09

Jay Lieske