Нет единой команды.Самое короткое из известных мне - которые группируют все , а не только максимальное значение в качестве промежуточного значения - это
xs.groupBy(f).maxBy(_._1)._2
. Для большей эффективности складки являются хорошими инструментами общего назначения для поискасуммы и максимумы и различные подобные вещи.По сути, всякий раз, когда вам нужно перебрать свою коллекцию, набирая какой-то ответ, используйте фолд.В этом случае
(xs.head /: xs.tail) {
(biggest, next) => if (f(biggest) < f(next)) next else biggest
}
выполнит 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
сделает это только с однимоценка за элемент.Если вы хотите сохранить последовательность, вы можете изменить ее на
(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
}
, чтобы сохранить список (соответствующая форма одноразовой оценки оставлена читателю в качестве упражнения).
Наконецдаже версия с почти максимальной эффективностью не является , которой трудно управлять, если вы хотите использовать несколько изменяемых переменных (надеюсь, хорошо скрытых в блоке кода, как у меня здесь)
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
}
(это будет возвращаться в обратном порядке, между прочим).