Scala成语通过多个标准排序
我想做这样的事情:
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] *)签名,它采用可比较的变量,并选择第一个非零。 解决方法
使用Ordering而不是Ordered通常更好。订购是一个类型类,比订单更灵活(如果只是因为Ordered必须通过类型来实现比较,而使用Ordering可以在外部定义)。要定义类型的自然排序(默认排序实例),您只需在协同对象中定义隐式排序值。
所以,足够的序言。好的是,当使用Ordering你想做的是很简单的,因为元组的隐含排序(假设元组元素本身有一个顺序)`: object Foo { implicit val FooOrdering = Ordering.by{ foo: Foo => (foo.length,foo.x,foo.y,foo.z) } } 此外,还有一个隐式转换,它将具有Ordering类型类实例的任何值转换为Ordered值(请参阅Ordered.orderingToOrdered),因此我们没有任何特别要求可以将Foo的任何实例传递给一个函数,期望一个有序的[Foo]) 更新:关于你的新问题:
一种方法是使用大部分基于Ordering.by和转换为元组的相同技术,但明确地将订单传递给组合: 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,byZOrdering) CompositeOrdering.apply基本上是你所说的Ordering.multipleBy在你的问题。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |