给定两个相同元组的元组,我如何按字典顺序比较它们?看起来这应该像下面的代码片段一样简单,但事实并非如此。有什么简单的例子来说明如何做到这一点?
var x = (1,2,3) < (1,2,4)
如果它们是列表,我可以定义一个递归函数来比较列表的头部,直到发现差异或列表结尾,但我认为我不能为元组做到这一点。
这并不简单,因为虽然
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)
这些额外的隐式不是自动可用的,因为它们在某些情况下会导致不同的隐式。
如果您想使用 Daniel 的解决方案,<
但如果您需要一种compare
方法,您可以执行以下操作(例如)。
implicitly[Ordering[Tuple2[Int, Int]]].compare((1,2), (2,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 函数(请参阅文档)并允许您获取元组上的迭代器。通过这种方式,您可以像使用列表一样编写函数。
编辑3: 这将是这样的:
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]。所以你必须定义一个 compare(Any,Any) 函数来处理你想要的。