Я не знаю способа сделать это за один проход коллекции без использования изменяемой переменной.С двумя проходами вы можете сделать это, используя foldLeft
, как в:
def updateFirst[A](list:List[A])(predicate:A => Boolean, newValue:A):List[A] = {
list.foldLeft((List.empty[A], predicate))((acc, it) => {acc match {
case (nl,pr) => if (pr(it)) (newValue::nl, _ => false) else (it::nl, pr)
}})._1.reverse
}
Идея состоит в том, что foldLeft
позволяет передавать дополнительные данные через итерацию.В этой конкретной реализации я изменяю предикат на фиксированный, который всегда возвращает false
.К сожалению, вы не можете построить List
из головы эффективным способом, поэтому для этого требуется еще один проход для reverse
.
. Я считаю, что очевидно, как сделать это, используя комбинацию map
иvar
Примечание : производительность List.map
такая же, как и при одном проходе по списку, только потому, что внутренняя стандартная библиотека является изменчивой.В частности, класс cons ::
объявлен как
final case class ::[B](override val head: B, private[scala] var tl: List[B]) extends List[B] {
, поэтому tl
на самом деле var
, и это используется реализацией map
для эффективного построения списка из головы.,Поле равно private[scala]
, поэтому вы не можете использовать тот же трюк за пределами стандартной библиотеки.К сожалению, я не вижу других API-вызовов, позволяющих использовать эту функцию, чтобы уменьшить сложность вашей проблемы за один проход.