gpt4 book ai didi

scala - Scala习惯用法,用于通过多个条件进行排序

转载 作者:行者123 更新时间:2023-12-03 12:30:01 26 4
gpt4 key购买 nike

我想做这样的事情:

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(ordering: Ordered[A]*)签名这样的东西,它采用可比变量,并选择第一个非零值。

最佳答案

通常,最好使用Ordering而不是OrderedOrdering是类型类,并且比Ordered灵活得多(如果仅因为Ordered必须由类型实现才能进行比较,而Ordering则可以在外部进行定义)。要为您的类型定义自然排序(默认Ordering实例),您只需在随播对象中定义一个隐式排序值。

因此,足够的序言。令人高兴的是,当使用Ordering时,您想要做的事情非常简单,因为元组具有隐式排序(前提是元组元素本身具有排序)`:

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

此外,还有一个隐式转换,它将具有 Ordering类型类实例的任何值转换为 Ordered值(请参见 Ordered.orderingToOrdered),因此我们无需特殊操作即可自动地将 Foo的任何实例传递给期望 Ordered[Foo])

更新:关于您的新问题:

Slightly related - is there any way to compose orderings?



一种实现方法是使用基于 Ordering.by的大多数相同技术并将其转换为元组,但是显式地将顺序传递给compose:
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基本上就是您在问题中所说的 Ordering.multipleBy

关于scala - Scala习惯用法,用于通过多个条件进行排序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14695833/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com