为什么maxBy只返回单项?

Mic*_*ael 5 collections scala

跟进这个问题,我不知道为什么 maxByTraversable[T]返回一个值T,而不是一个序列T(列表或类似).这看起来很常见.例如(来自上一个问题):

有关成绩的学生名单

List(Student("Mike", "A"), Student("Pete", "B"), Student("Paul", A))"

我想得到

List(Student("Mike", "A"), Student("Paul", A))

有没有人知道任何标准实现maxBy,它返回一系列找到的项目?

Rex*_*err 6

没有单一的命令.我所知道的最短 - 将所有东西分组,而不仅仅是作为中间体的最大值 -

xs.groupBy(f).maxBy(_._1)._2
Run Code Online (Sandbox Code Playgroud)

为了提高效率,折叠是用于查找总和和最大值以及各种类似事物的通用工具.基本上,任何时候你需要在积累一些答案时跑过你的收藏,使用折叠.在这种情况下,

(xs.head /: xs.tail) {
  (biggest, next) => if (f(biggest) < f(next)) next else biggest
}
Run Code Online (Sandbox Code Playgroud)

maxBy(f)如果您不介意为每个元素重新评估该函数两次,则会执行

((xs.head, f(xs.head)) /: xs.tail) {
  case (scored, next) =>
    val nextscore = f(next)
    if (scored._2 < nextscore) (next, nextscore)
    else scored
}._1
Run Code Online (Sandbox Code Playgroud)

将每个元素只进行一次评估.如果要保留序列,可以将其修改为

(Seq(xs.head) /: xs.tail) {
  (bigs, next) =>
    if (f(bigs.head) > f(next)) bigs
    else if (f(bigs.head) < f(next)) Seq(next)
    else bigs :+ next
}
Run Code Online (Sandbox Code Playgroud)

保留列表(相应的单一评估表格留给读者练习).

最后,即使是接近最大效率的版本是不是所有很难管理,如果你愿意使用一些可变的变量(希望精心隐藏在一个代码块像我这里)

val result = {
  var bigs = xs.take(0).toList
  var bestSoFar = f(xs.head)
  xs.foreach{ x =>
    if (bigs.isEmpty) bigs = x :: bigs
    else {
      val fx = f(x)
      if (fx > bestSoFar) {
        bestSoFar = fx
        bigs = List(x)
      }
      else if (fx == bestSoFar) bigs = x :: bigs
    }
  }
  bigs
}
Run Code Online (Sandbox Code Playgroud)

(这将以相反的顺序返回,顺便说一下).