У меня есть Список дней в месяце:
val days = List(31, 28, 31, ...)
Я должен возвратить Список с совокупной суммой дней:
val cumDays = List(31, 59, 90)
Я думал об использовании оператора сгиба:
(0 /: days)(_ + _)
но это только возвратит конечный результат (365), тогда как мне нужен список промежуточных результатов.
Так или иначе я могу сделать это изящно?
Сложить в список вместо целого числа. Используйте пару (неполный список с накопленными значениями, аккумулятор с последней суммой) в качестве состояния в сгибе.
Сверните ваш список в новый список. На каждой итерации добавляйте значение, которое является суммой заголовка + следующего ввода. Затем все переверните.
scala> val daysInMonths = List(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)
daysInMonths: List[Int] = List(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)
scala> daysInMonths.foldLeft(Nil: List[Int]) { (acc,next) =>
| acc.firstOption.map(_+next).getOrElse(next) :: acc
| }.reverse
res1: List[Int] = List(31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365)
Я не уверен, почему все, кажется, настаивают на использовании какого-то складывания, в то время как вы в основном хотите отобразить значения в суммарные значения...
val daysInMonths = List(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)
val cumulated = daysInMonths.map{var s = 0; d => {s += d; s}}
//--> List[Int] = List(31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365)
В Scala 2.8 есть методы scanLeft
и scanRight
, которые делают именно это.
Для 2.7 вы можете определить свой собственный scanLeft
вот так:
def scanLeft[a,b](xs:Iterable[a])(s:b)(f : (b,a) => b) =
xs.foldLeft(List(s))( (acc,x) => f(acc(0), x) :: acc).reverse
А затем использовать его вот так:
scala> scanLeft(List(1,2,3))(0)(_+_)
res1: List[Int] = List(0, 1, 3, 6)
Работает на 2.7.7:
def stepSum (sums: List [Int], steps: List [Int]) : List [Int] = steps match {
case Nil => sums.reverse.tail
case x :: xs => stepSum (sums.head + x :: sums, steps.tail) }
days
res10: List[Int] = List(31, 28, 31, 30, 31)
stepSum (List (0), days)
res11: List[Int] = List(31, 59, 90, 120, 151)