给定两个元素数量相同的元组,如何进行词典顺序比较?似乎应该像下面的代码片段一样简单,但实际上并不是。有没有简单的示例可以说明如何做到这一点?
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
方法,可以像下面这样做(例如)。
Daniel的解决方案适用于使用<
的情况,但如果您需要一个compare
方法,则可以执行以下操作(例如)。
implicitly[Ordering[Tuple2[Int, Int]]].compare((1,2), (2,3))
对于所有具有可比较部分的元组,都定义了顺序。
最简单的方法是在它们上面定义一个隐式的Ordering[T],但是你必须将这个排序器传递给sort函数(或任何其他想要进行比较的函数)。还可以通过隐式传递它。
另一种方法是通过隐式转换扩展元组类的<操作符:
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)) = ...
}
编辑2: 如果您还需要比较不同大小的元组,可以使用所有元组类中定义的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)函数来处理你想要的内容。
-Xexperimental
选项,这将选择LUB而不是Any
。 - soc
import scala.math.Ordered.orderingToOrdered
导入,它就能工作 https://dev59.com/JWIk5IYBdhLWcg3wWtFz - Moodragonx