18

给定两个相同元组的元组,我如何按字典顺序比较它们?看起来这应该像下面的代码片段一样简单,但事实并非如此。有什么简单的例子来说明如何做到这一点?

var x = (1,2,3) < (1,2,4)

如果它们是列表,我可以定义一个递归函数来比较列表的头部,直到发现差异或列表结尾,但我认为我不能为元组做到这一点。

4

3 回答 3

27

这并不简单,因为虽然

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)

这些额外的隐式不是自动可用的,因为它们在某些情况下会导致不同的隐式。

于 2012-06-19T15:41:37.213 回答
14

如果您想使用 Daniel 的解决方案,<但如果您需要一种compare方法,您可以执行以下操作(例如)。

implicitly[Ordering[Tuple2[Int, Int]]].compare((1,2), (2,3))

为具有可比部分的所有元组定义了排序。

于 2012-09-05T22:03:54.443 回答
2

最简单的方法是在它们上定义一个隐式 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) 函数来处理你想要的。

于 2012-06-19T13:54:09.870 回答