#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 безопаснее