Вот хвостовой рекурсией реализация для списка с помощью аккумулятора:
import scala.annotation.tailrec
def dropNth[A](lst: List[A], n: Int): List[A] = {
@tailrec
def dropRec(i: Int, lst: List[A], acc: List[A]): List[A] = (i, lst) match {
case (_, Nil) => acc
case (1, x :: xs) => dropRec(n, xs, acc)
case (i, x :: xs) => dropRec(i - 1, xs, x :: acc)
}
dropRec(n, lst, Nil).reverse
}
Обновление: Как отмечалось в комментариях, я пробовал другие решения здесь на большом входе (1 to 5000000).toList
. Те, у кого zipWithIndex filter/collect
выходят из строя на OutOfMemoryError
, и (не-хвост) рекурсивный сбой на StackOverflowError
. Шахта, использующая список cons (::
) и tailrec
, хорошо работает.
Это потому, что индекс zping-with-index создает новый ListBuffer
и добавляет кортежи, что приводит к OOM
. И рекурсивный просто имеет 5 миллионов уровней рекурсии, что слишком много для стека.
Рекурсивный хвост не создает ненужных объектов и эффективно создает две копии ввода (то есть 2 * 5 миллионов экземпляров ::
), как в O(n)
.Во-первых, это создание фильтрованных элементов, которые находятся в обратном порядке, потому что выход добавляется x :: acc
(в O(1)
, а добавление List
- O(n)
). Второй - это просто обратный рекурсивный вывод.
Возможный дубликат http://stackoverflow.com/questions/18847249/how-to-remove-an-item-from-a-list-in-scala-having-only-its-index? – GuiSim