Как лексикографически сравнивать кортежи scala?
Учитывая два кортежа одной и той же ясности, как я могу их сравнить с лексикографией? Кажется, что это должно быть так же просто, как в следующем фрагменте, но это не так. Любой простой пример того, как это сделать?
var x = (1,2,3) < (1,2,4)
Были ли они списки, я мог бы определить рекурсивную функцию, которая бы сравнивала голову списков, пока не была найдена разница или конец списка, но я не думаю, что могу сделать это для кортежей.
Ответы
Ответ 1
Это не просто, потому что пока
var x = (1,2,3) < (1,2)
выглядит довольно просто,
var x = (1,false,3) < (1,2)
нет. Как вы относитесь к не упорядоченным типам? Как вы относитесь к разным типам в одной и той же позиции кортежа?
Предоставляете ли вы, чтобы все типы были одинаковыми? В этом случае у вас нет кортежа. Вся суть кортежа состоит в том, что его арность фиксирована (вы статически знаете, насколько она велика), и каждый элемент может быть другого типа.
Если бы я столкнулся с этой проблемой - и я бы очень старался не делать этого - я бы захватил Shapeless, превратил кортежи в нечто вроде HLists, а затем попытаюсь сравнить это.
ИЗМЕНИТЬ
А, теперь это намного проще:
import scala.math.Ordering.Implicits._
var x = (1,2,3) < (1,2,4)
Эти дополнительные импликации не доступны автоматически, поскольку в некоторых случаях они могут привести к расплывчатым имплицитам.
Ответ 2
Решение Daniel работает, если вы хотите использовать <
, но если вам нужен метод compare
, вы можете сделать следующее (например).
implicitly[Ordering[Tuple2[Int, Int]]].compare((1,2), (2,3))
Определены порядки для всех кортежей со сравнимыми частями.
Ответ 3
Самый простой способ - определить неявный Ordering [T] на них, но тогда вы должны передать это упорядочение функции сортировки (или любую другую функцию, которая хочет их сравнить). Это также можно передать неявно.
Другим способом было бы: расширить класс кортежа на < оператор через неявный листинг:
implicit def compareTuple[T](lhs: (T,T)) = new {
def <(rhs: (T,T)) = lhs._1<rhs._1 || (lhs._1==rhs._1 && lhs._2<rhs._2)
}
изменить
Если вы хотите иметь и другие операторы сравнения, вы можете получить их, наследуя от Ordered [T]:
implicit def compareTuple[T](lhs: (T,T)) = new Ordered[(T,T)] {
def compare(rhs: (T,T)) = ...
}
edit2:
Если вам также нужно сравнить кортежи разных размеров, вы можете использовать функцию productIterator, которая определена во всех классах кортежей (см. Документацию) и позволяет вам чтобы получить итератор над кортежем. Таким образом, вы можете написать такую функцию, как если бы вы сделали это со списком.
Edit3:
Это будет примерно так:
implicit def compareTuple[T <: Product](lhs: T) = new Ordered[T] {
def compare[U <: Product](rhs: U) = {
def compare(lhs: Any, rhs: Any) = ...
def iteratorCompare(lhs: Iterator[Any], rhs: Iterator[Any]):Int =
if(!lhs.hasNext)
if(!rhs.hasNext)
0
else
-1
else if(!rhs.hasNext)
1
else
compare(lhs.next,rhs.next)
iteratorCompare(lhs.productIterator,rhs.productIterator)
}
}
Но при таком подходе вам нужно позаботиться о типах. Поскольку функция не знает типы элементов кортежа (они могут быть разными внутри одного и того же кортежа), он может предоставить только Iterator [Any]. Поэтому вам нужно определить функцию сравнения (Any, Any) для обработки того, что вы хотите.