如何按字母顺序比较scala元组?

时间:2012-06-19 13:48:46

标签: scala tuples

考虑到同一个元组的两个元组,我如何按字典顺序比较它们?看起来这应该像下面的代码片段一样简单,但事实并非如此。有关如何操作的简单示例吗?

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

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

3 个答案:

答案 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)函数来处理你想要的东西。