В идеале вы хотите пройти по списку только один раз и в ходе каждого отдельного Int, вы хотите увеличить счетчик (частоту), а также отслеживать минимальный разрыв.
Вы можете использовать класс case для хранения частоты и минимального разрыва, сохраненное значение будет неизменным. Обратите внимание, что minGap не может быть определен.
case class Metric(frequency: Int, minGap: Option[Int])
В общем случае вы можете использовать Map[Int, Metric]
для поиска Metric
неизменяемого объекта. Поиск минимального зазора является более сложной частью. Чтобы найти пробел, вы можете использовать метод sliding(2)
. Он будет перемещаться по списку с помощью скользящего окна размера два, позволяющего сравнить каждое Int с его предыдущим значением, чтобы вы могли вычислить разрыв.
Наконец, вам нужно накапливать и обновлять информацию при прохождении списка. Это можно сделать, сложив каждый элемент списка во временный результат, пока вы не пройдете весь список и не получите полный результат.
Собираем вещи вместе:
listVar.sliding(2).foldLeft(
Map[Int, Metric]().withDefaultValue(Metric(0, None))
) {
case (map, List(a, b)) =>
val metric = map(b)
val newGap = metric.minGap match {
case None => math.abs(b - a)
case Some(gap) => math.min(gap, math.abs(b - a))
}
val newMetric = Metric(metric.frequency + 1, Some(newGap))
map + (b -> newMetric)
case (map, List(a)) =>
map + (a -> Metric(1, None))
case (map, _) =>
map
}
Результат для listVar: List [Int] = List (2, 2, 4, 4, 0, 2, 2, 2, 4, 4)
scala.collection.immutable.Map[Int,Metric] = Map(2 -> Metric(4,Some(0)),
4 -> Metric(4,Some(0)), 0 -> Metric(1,Some(4)))
Затем вы можете превратить результат в нужный класс элементов, используя map.toSeq.map((i, m) => new Item(i, m.frequency, m.minGap.getOrElse(-1)))
.
В процессе вы также можете создать непосредственно свой объект Item, но я думал, что код будет сложнее читать.