Как передать начальное значение в foldLeft из отфильтрованного списка с цепочкой функций?

#scala #functional-programming

#scala #функциональное программирование

Вопрос:

Допустим, у меня есть List . Я filter делаю это сначала при некотором условии. Теперь я хочу передать начальное значение из этого отфильтрованного массива во foldLeft all, связывая оба вместе. Есть ли способ сделать это?

Например:

 scala> val numbers = List(5, 4, 8, 6, 2)
val numbers: List[Int] = List(5, 4, 8, 6, 2)

scala> numbers.filter(_ % 2 == 0).foldLeft(numbers(0)) { // this is obviously incorrect since numbers(0) is the value at index 0 of the original array not the filtered array
     |   (z, i) => z   i
     | }
val res88: Int = 25
  

Комментарии:

1.Может быть, просто используйте reduceLeft или даже лучше, вы можете просто .sum . Еще лучше делать все за один раз numbers.withFilter(_ % 2 == 0).sum ( withFiler это лениво, если у вас есть еще много шагов, вы можете использовать итератор вместо этого, поэтому все шаги оцениваются лениво). — Кстати, вызов списка массивом сбивает с толку.

2. Использование первого элемента для сгиба довольно необычно, обычно используется ноль (или какой-либо другой элемент, служащий «пустым» для операции сгиба). Вы действительно уверены, что хотите это сделать?

3. @Suma @jwvh Это был просто упрощенный пример, я намерен использовать foldLeft так, но не так, как я показал в примере фрагмента кода.

Ответ №1:

Вы могли бы просто сопоставить шаблон с результатом фильтрации, чтобы получить первый элемент списка (head) и остальные (tail):

 val numbers = List(5, 4, 8, 6, 2)

val result = numbers.filter(_ % 2 == 0) match {
  case head :: tail => tail.foldLeft(head) {
        (z, i) => z   i
  }
   // here you need to handle the case, when after filtering there are no elements, in this case, I just return 0
  case Nil => 0
}
  

Вы также могли бы просто использовать reduce:

 numbers.filter(_ % 100 == 0).reduce {
   (z, i) => z   i
}
  

но это вызовет исключение в случае, если после фильтрации список пуст.

Комментарии:

1. Или просто case nonempty @ _ :: _ => nonempty.reduce ?

2. вы не можете уменьшить пустую коллекцию — это выдаст ошибку => foldLeft безопаснее