Как элегантно сравнить кортежи в Свифт?

У меня есть 2 разных набора типа (Double, Double):

let tuple1 : (Double, Double) = (1,2)
let tuple2 : (Double, Double) = (3,4)

Я хочу сравнить их значения с помощью простого оператора if. Что-то вроде:

if (tuple1 == tuple2){
    // Do stuff
}

Это вызывает следующую ошибку:

Не удалось найти перегрузку для '==', которая принимает поставляемую Аргументы

Мое текущее решение - это такая функция:

func compareTuples <T:Equatable> (tuple1:(T,T),tuple2:(T,T)) -> Bool{
    return (tuple1.0 == tuple2.0) && (tuple1.1 == tuple2.1)
}

Мне действительно не нравится это решение и поиск чего-то более элегантного. Я уже пытался написать расширение, но не могу заставить его работать для кортежей. У вас есть хорошее решение этой проблемы?

Ответы

Ответ 1

Попробуйте следующее:

func == <T:Equatable> (tuple1:(T,T),tuple2:(T,T)) -> Bool
{
   return (tuple1.0 == tuple2.0) && (tuple1.1 == tuple2.1)
}

Он точно такой же, как ваш, но я назвал его ==. Затем такие вещи, как:

(1, 1) == (1, 1)

истинны и

(1, 1) == (1, 2)

являются ложными

Ответ 2

Я согласен, что такого поведения не ожидается, поскольку кортежи можно сравнивать на разных языках, таких как Python и Haskell, но в соответствии с официальной документацией:

Примечание

Кортежи полезны для временных групп связанных значений. Они не подходит для создания сложных структур данных. Если ваши данные структура, вероятно, будет сохраняться за пределами временной области, класса или структуры, а не как кортеж. Для получения дополнительной информации см. Классы и структуры.

Таким образом, это может быть эквивалент Swift: "вы неправильно держите телефон", но по текущим рекомендациям, идиоматический способ сделать это - определить класс или конструкцию (или даже Enum) с реализацией Comparable для обеспечения == и связанных операторов.

Ответ 3

Swift 4 поддерживает сравнение кортежей. Вы больше не получите ошибку.

Этот код отлично работает

let tuple1 : (Double, Double) = (1,2)
let tuple2 : (Double, Double) = (3,4)

if (tuple1 == tuple2) {
    print("equal")
}
else {
    print("unequal")
}

Здесь неравное напечатано на консоли детской площадки.

Одно из ограничений в сравнении кортежей, как упомянуто в документе Apple, -

Стандартная библиотека Swift включает операторы сравнения кортежей для кортежи с менее чем семью элементами. Сравнить кортежи с семью или больше элементов, вы должны реализовать операторы сравнения самостоятельно.

Ответ 4

В быстром есть кортежи, как мы знаем. Кортежи можно сравнивать друг с другом с помощью стандартных операторов С. Кортежи сравниваются друг с другом от LEFT до RIGHT

if (1,"death") < (3,"life") {   
     print("Life is better than death") // this is true
}

Swift только сравнивает целочисленные значения 1 и 3. То, что Swift не сравнивает строки смерти и жизни. Он будет сравнивать их только тогда, когда первые элементы кортежа будут одинаковыми.

if (99,"life") < (99,"death") {   
     print("Life is better than death") // this is false
}

В приведенном выше случае swift не сравнивает целочисленные значения 99, вместо этого он будет сравнивать жизнь и смерть. Дополнительно: Swift может сравнивать только кортежи, которые имеют максимум 6 элементов. Более 6 элементов вы должны сравнить самостоятельно.

Ответ 5

Похожий на ответ @JeremyP, но более общий:

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

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

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

Ответ 6

Следующий подход сравнивает кортеж любого числа членов любого размера, если они не содержат типы сбора, такие как Array и Dictionary

import Darwin // or Foundation
/// here we go
func memeq<T>(var lhs:T, var rhs:T)->Bool {
    return withUnsafePointers(&lhs, &rhs) {
        memcmp($0, $1, UInt(sizeof(T)))
    } == 0
}

let l = (false, 42,  log(exp(1.0)))
let r = (!true, 6*7, exp(log(1.0)))
println(memeq(l, r))   // expectedly true
let l2 = (0, [0])
let r2 = (0, [0])
println(memeq(l2, r2)) // unfortunately false

Типы записей уже проверены с помощью дженериков. Если они отличаются друг от друга, он даже не компилируется благодаря проверке типов.