Как элегантно сравнить кортежи в Свифт?
У меня есть 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
Типы записей уже проверены с помощью дженериков. Если они отличаются друг от друга, он даже не компилируется благодаря проверке типов.