В Scala, как я сворачиваю Список и возвращаю промежуточные результаты?

У меня есть Список дней в месяце:

val days = List(31, 28, 31, ...)

Я должен возвратить Список с совокупной суммой дней:

val cumDays = List(31, 59, 90)

Я думал об использовании оператора сгиба:

(0 /: days)(_ + _)

но это только возвратит конечный результат (365), тогда как мне нужен список промежуточных результатов.

Так или иначе я могу сделать это изящно?

29
задан lindelof 11 July 2010 в 22:48
поделиться

5 ответов

Сложить в список вместо целого числа. Используйте пару (неполный список с накопленными значениями, аккумулятор с последней суммой) в качестве состояния в сгибе.

2
ответ дан 28 November 2019 в 00:55
поделиться

Сверните ваш список в новый список. На каждой итерации добавляйте значение, которое является суммой заголовка + следующего ввода. Затем все переверните.

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)
1
ответ дан 28 November 2019 в 00:55
поделиться

Я не уверен, почему все, кажется, настаивают на использовании какого-то складывания, в то время как вы в основном хотите отобразить значения в суммарные значения...

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)
18
ответ дан 28 November 2019 в 00:55
поделиться

В 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)
54
ответ дан 28 November 2019 в 00:55
поделиться

Работает на 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)
0
ответ дан 28 November 2019 в 00:55
поделиться
Другие вопросы по тегам:

Похожие вопросы: