当前位置: 首页 > 知识库问答 >
问题:

按多个条件排序的Scala习惯用法

慕鹏
2023-03-14

我想这样做:

class Foo extends Ordered[Foo] {
   val x
   val y
   val z
   .
   .
   .
   .
   def compare(that: Foo) = {
      val c0 = this.length compareTo that.length          // primary comparison
      lazy val c1 = this.x compareTo that.x               // secondary comparison
      lazy val c2 = this.y.size compareTo that.y.size     // tertiary comparison
      lazy val c3 = this.z.head compareTo that.z.head     // final tie breaker
      if (c0 != 0) c0 else if (c1 != 0) c1 else if (c2 != 0) c2 else if (c3 != 0) c3 else c4
   }    
}

我在想有没有更干净的方法来写这种东西。我期待一些东西像Ordering.multipleBy(排序:有序[A]*)签名,它需要一个可比变量并选择第一个非零。

共有3个答案

雷锋
2023-03-14

我能想到的最好的办法是:

def compare(that: Foo) = multiCompare(
  this.length compareTo that.length      // primary comparison
  this.x      compareTo that.x,          // secondary comparison
  this.y.size compareTo that.y.size,     // tertiary comparison
  this.z.head compareTo that.z.head,     // final tie breaker
)

def multiCompare(c: ( => Int)*) = c find {_ != 0} getOrElse 0
班玉堂
2023-03-14

如果你想要最高速度——我知道不是你要求的!-并且仍然清晰,你可以

def compare(that: Foo): Int = {
  this.length compareTo that.length match { case 0 =>; case c => return c }
  this.x      compareTo that.x      match { case 0 =>; case c => return c }
  this.y.size compareTo that.y.size match { case 0 =>; case c => return c }
  this.z.head compareTo that.z.head match { case 0 =>; case c => return c }
  0
}

还有各种基于收集的解决方案和其他解决方案,我将留给其他人来解释。(注意所有的样板文件,并注意到您真正需要知道的是每种情况下的。.length,例如,这会激发比较。)

桂飞翼
2023-03-14

通常最好使用订购而不是订购订购是一个类型类,比订购灵活得多(如果只是因为订购必须由类型实现要比较,而与订购,您可以在外部定义此)。要为类型定义自然排序(默认的Ordle实例),只需在伴随对象中定义一个隐式排序值。

所以,序言就够了。很好的一点是,当使用排序时,您想要做的事情非常简单,因为元组有一个隐式排序(前提是元组元素本身有一个排序)`:

object Foo {
  implicit val FooOrdering = Ordering.by{ foo: Foo => 
    (foo.length, foo.x, foo.y, foo.z) 
  }
}

此外,还有一种隐式转换,它将任何具有Ordering类型类实例的值转换为Ordered值(请参见Ordered.orderingtooordered),因此我们没有什么特殊的事情可以自动将Foo的任何实例传递给期望有序的函数[Foo]

更新:关于你的新问题:

稍微相关-是否有任何方法来编写订单?

一种方法是基于排序使用几乎相同的技术。通过和转换为元组,但显式传递要组合的顺序:

val byXOrdering = Ordering.by{ foo: Foo => foo.x }
val byYOrdering = Ordering.by{ foo: Foo => foo.y }
val byZOrdering = Ordering.by{ foo: Foo => foo.z }

// Compose byXOrdering and byYOrdering:
val byXThenYOrdering = Ordering.by{ foo: Foo => (foo, foo) }(Ordering.Tuple2(byXOrdering, byYOrdering))

// Compose byXOrdering and byYOrdering and byZOrdering:
val byXThenYThenZOrdering = Ordering.by{ foo: Foo => (foo, foo, foo) }(Ordering.Tuple3(byXOrdering, byYOrdering, byZOrdering))

但它相对“嘈杂”。仅使用标准库无法找到更好的方法,因此我建议使用我们自己的助手:

final class CompositeOrdering[T]( val ord1: Ordering[T], val ord2: Ordering[T] ) extends Ordering[T] {
  def compare( x: T, y: T ) = {
    val comp = ord1.compare( x, y )
    if ( comp != 0 ) comp else ord2.compare( x, y )
  }
}
object CompositeOrdering {
  def apply[T]( orderings: Ordering[T] * ) = orderings reduceLeft (_ orElse _)
}
implicit class OrderingOps[T]( val ord: Ordering[T] ) extends AnyVal {
  def orElse( ord2: Ordering[T] ) = new CompositeOrdering[T]( ord, ord2 )
}

可以这样使用:

val byXOrdering = Ordering.by{ foo: Foo => foo.x }
val byYOrdering = Ordering.by{ foo: Foo => foo.y }
val byZOrdering = Ordering.by{ foo: Foo => foo.z }

// Compose byXOrdering and byYOrdering:
val byXThenYOrdering = byXOrdering orElse byYOrdering

// Compose byXOrdering and byYOrdering and byZOrdering:
val byXThenYThenZOrdering = byXOrdering orElse byYOrdering orElse byZOrdering

或者更简单,像这样:

// Compose byXOrdering and byYOrdering:
val byXThenYOrdering = CompositeOrdering(byXOrdering, byYOrdering)

// Compose byXOrdering and byYOrdering and byZOrdering:
val byXThenYThenZOrdering = CompositeOrdering(byXOrdering, byYOrdering, byZOrdering)

CompositeOrdering。apply基本上就是您所说的排序。在您的问题中使用multipleBy

 类似资料:
  • 问题内容: 我有一个列表,其中每个元素都是形式。例如,列表的元素可能看起来像这样。 我想通过以下条件对包含描述的元素类型的列表进行排序: 如果两个元素的整数列表(即)的长度不同,则整数列表较小的元素是较小的元素。 否则,如果整数列表的长度相同,则较小的元素是第一个整数的较小整数,这两个元素的整数列表都不同。例如: [[1,1,99,100],-1] <[[1,1,100,1],-1],因为99 <

  • 我想写一个查询,它将根据多个条件对结果进行排序。 请参考下表 我想在表上方排序 1-通过已知域后跟然后Rest。 所以我想把结果行分成三部分。 第一部分的行具有作为域,然后在第二部分的行中,最后剩下的行具有域。 2-按字母顺序排列,所有特殊字符位于末尾。 每个部分都应该在字段上按字母顺序进一步排序,末尾有特殊字符。 结果应如下表所示。 我已经用下面的查询按字母顺序对结果进行排序,底部有特殊符号,但

  • 我有以下代码: 我的问题是我想让我的列表按多个东西排序: 1。)将它们分组为未来事件和过去事件(通过检查ystem.current毫秒()是否大于结束时间戳)2。)通过开始升序排序未来事件3。)通过结束降序排序过去事件 我可以用Java 8 Lambda来做这件事吗?或者我需要另一种排序项目的方法吗?

  • 问题内容: 我有一个包含Quote对象的数组列表。我希望能够按名称,更改和更改百分比的字母顺序进行排序。如何排序我的数组列表? 问题答案: 创建一个合适的对象,它将根据你所需的条件比较两个项目。然后在你的上使用 。 如果以后要按其他条件排序,请使用不同的再次调用。

  • 问题内容: 我正在尝试做一个标准查询,该查询返回像常见问题一样的stackoverflow中回答最多的问题。 一个问题包含多个答案。 我试图以标准查询返回按每个问题的答案数排序的最常回答的问题。 有人知道我应该在hibernate标准util中使用什么吗? 问题答案: 这将返回一个Object []列表。每个Object []都将问题的ID作为第一个元素,并将此问题的答案数目作为第二个元素。问题按

  • 问题内容: 请帮助我创建一个包含10个’where’子句的select查询,其顺序应为:查询结果应按大多数关键字(where条件)匹配到最不匹配的顺序显示。 注意:所有10个条件都带有“或”。 请帮助我创建此查询。我正在使用MS-SQL Server 2005 喜欢: 在上面的查询中,所有与最大条件匹配的记录都应位于顶部,而较少匹配条件的记录应位于底部。 问题答案: