考虑到同一个元组的两个元组,我如何按字典顺序比较它们?看起来这应该像下面的代码片段一样简单,但事实并非如此。有关如何操作的简单示例吗?
var x = (1,2,3) < (1,2,4)
如果他们列出,我可以定义一个递归函数来比较列表的头部,直到找到差异或列表的结尾,但我认为我不能为元组做到这一点。
答案 0 :(得分:23)
这并不简单,因为
var x = (1,2,3) < (1,2)
看起来很简单,
var x = (1,false,3) < (1,2)
不是。你如何处理非订购类型?你如何处理同一元组位置的不同类型?
你要求所有类型都一样吗?在这种情况下,你没有元组。元组的重点是它的arity是固定的(你静态知道它有多大),每个元素可以是不同的类型。
如果我发现自己遇到了这个问题 - 我会非常努力不去 - 我会抓住Shapeless,将元组转换成类似于HLists的东西,然后尝试比较它。
修改强>
啊,现在更容易了:
import scala.math.Ordering.Implicits._
var x = (1,2,3) < (1,2,4)
这些额外的含义不会自动提供,因为在某些情况下它们会导致不同的含义。
答案 1 :(得分:13)
如果您想使用<
,Daniel的解决方案有效,但如果您需要compare
方法,则可以执行以下操作(例如)。
implicitly[Ordering[Tuple2[Int, Int]]].compare((1,2), (2,3))
为所有具有可比较部分的元组定义了排序。
答案 2 :(得分:2)
最简单的方法是在它们上定义一个隐式的Ordering [T],但是你必须将这个顺序传递给sort函数(或任何其他想要比较它们的函数)。也可以隐式传递它。
另一种方法是,通过&lt;扩展元组类。运算符通过隐式转换:
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:强> 如果您还需要比较不同大小的元组,可以使用在所有元组类(see documentation)中定义的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)
}
}
但是使用这种方法你必须要注意这些类型。因为函数不知道元组元素的类型(它们可以在同一元组内部不同),所以它只能为您提供迭代器[Any]。所以你必须定义一个比较(Any,Any)函数来处理你想要的东西。