scalaz.Foldable有一个maximumBy方法,可以在容器中找到 a 最大元素。但有没有一种优雅的方法来使用scalaz找到它们所有?即:
Vector(Person("Ben", 1), Person("Jil", 3), Person("Bob", 3)).maximumsBy(_.age)
== Vector(Person("Jil", 3), Person("Bob", 3))
我有一个问题,如果有几个相等的最大值,我想随机选择这些候选者。
答案 0 :(得分:2)
你可以做那样的事情
implicit def MaxNonEmptyListSemigroup[A : Order]:
Semigroup[NonEmptyList[A]] = new Semigroup[NonEmptyList[A]] {
def append(l1: NonEmptyList[A], l2: =>NonEmptyList[A]): NonEmptyList[A] =
Order[A].apply(l1.head, l2.head) match {
case GT => l1
case LT => l2
case EQ => l1 append l2
}
}
// returns None if the list is empty
// otherwise returns Some(non-empty-list of maximum elements)
list.foldMap1Opt(a => NonEmptyList.nels(a)) :: Option[NonEmptyList[A]]
答案 1 :(得分:0)
理想情况下,maximumsBy
将返回与提供的容器相同类型的最大值。为了有效地做到这一点,似乎需要scalaz.Reducer,一个类型化模型,用于对容器进行追加和前置建模。
import scalaz._
import Ordering._
import std.AllInstances._
object Maximums extends App {
def maximumsBy[F[_]: Foldable, A, B: Order](fa: F[A])(f: A => B)
(implicit r: Reducer[A, F[A]]): Option[F[A]] =
Foldable[F].foldMapLeft1Opt(fa)(a => (f(a), r.unit(a))) {
case (curr@(max, maxes), a) => {
val next = f(a)
Order[B].apply(next, max) match {
case GT => (next, r.unit(a))
case LT => curr
case EQ => (max, r.snoc(maxes, a))
}
}
}.map(_._2)
println(maximumsBy(Vector(("a", 1), ("c", 3), ("c", 3)))(_._2))
println(maximumsBy(List(("a", 1), ("c", 3), ("c", 3)))(_._2))
//Output:
//Some(Vector((c,3), (c,3)))
//Some(List((c,3), (c,3)))
}
我对于maximumsBy
最终的复杂程度感到有些沮丧。有没有办法简化它,同时保持相同的行为?