【发布时间】:2012-09-06 06:03:54
【问题描述】:
给定两个相同元组的元组,我如何按字典顺序比较它们?看起来这应该像下面的 sn-p 一样简单,但事实并非如此。有什么简单的例子吗?
var x = (1,2,3) < (1,2,4)
如果它们是列表,我可以定义一个递归函数来比较列表的头部,直到找到列表的差异或结尾,但我认为我不能为元组做到这一点。
【问题讨论】:
给定两个相同元组的元组,我如何按字典顺序比较它们?看起来这应该像下面的 sn-p 一样简单,但事实并非如此。有什么简单的例子吗?
var x = (1,2,3) < (1,2,4)
如果它们是列表,我可以定义一个递归函数来比较列表的头部,直到找到列表的差异或结尾,但我认为我不能为元组做到这一点。
【问题讨论】:
这并不简单,因为当
var x = (1,2,3) < (1,2)
看起来很简单,
var x = (1,false,3) < (1,2)
不是。你如何处理无序类型?同一个元组位置的不同类型如何处理?
您是否要求所有类型都相同?在这种情况下,您没有元组。元组的全部意义在于它的数量是固定的(你静态地知道它有多大)并且每个元素可以是不同的类型。
如果我发现自己有这个问题——而且我会努力避免——我会抓住 Shapeless,将元组转换成 HList 之类的东西,然后尝试比较。
编辑
啊,现在容易多了:
import scala.math.Ordering.Implicits._
var x = (1,2,3) < (1,2,4)
这些额外的隐式不会自动可用,因为它们在某些情况下会导致不同的隐式。
【讨论】:
import scala.math.Ordered.orderingToOrdered stackoverflow.com/questions/19345030/… 这样做,则可以使用
如果您想使用 <,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: 如果您还需要比较不同大小的元组,您可以使用在所有元组类 (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)
}
}
但是使用这种方法,您必须注意类型。因为该函数不知道元组元素的类型(它们在同一个元组中可以不同),所以它只能为您提供一个 Iterator[Any]。所以你必须定义一个 compare(Any,Any) 函数来处理你想要的。
【讨论】:
-Xexperimental,它将选择LUB而不是Any。