właśnie wprowadził Akumulatory
@tailrec def InsertSort(xs: List[Int], acc: List[Int] = Nil): List[Int] =
if (xs.nonEmpty) {
val x :: rest = xs
@tailrec
def insert(x: Int, sorted_xs: List[Int], acc: List[Int] = Nil): List[Int] =
if (sorted_xs.nonEmpty) {
val y :: ys = sorted_xs
if (x <= y) acc ::: x :: y :: ys else insert(x,ys, acc :+ y)
} else acc ::: List(x)
InsertSort(rest, insert(x, acc))
} else acc
:::
i :+
wezmą O (n) dla domyślnej implementacji List
, więc lepiej użyć bardziej odpowiedniej kolekcji (np. ListBuffer
). Możesz także przepisać go na foldLeft
zamiast jawnej rekursji.
Szybsze opcja (z foldLeft
bez :+
):
@tailrec
def insert(sorted_xs: List[Int], x: Int, acc: List[Int] = Nil): List[Int] =
if (sorted_xs.nonEmpty) {
val y::ys = sorted_xs
if (x <= y) acc.reverse ::: x :: y :: ys else insert(ys, x, y :: acc)
} else (x :: acc).reverse
scala> List(1,5,3,6,9,6,7).foldLeft(List[Int]())(insert(_, _))
res22: List[Int] = List(1, 3, 5, 6, 6, 7, 9)
I wreszcie z span
(jak w użytkownika @ roterl odpowiedź, ale span
jest trochę szybciej - przemierza kolekcji tylko do > x
występuje):
def insert(sorted_xs: List[Int], x: Int) = if (sorted_xs.nonEmpty) {
val (smaller, larger) = sorted_xs.span(_ < x)
smaller ::: x :: larger
} else x :: Nil
scala> List(1,5,3,6,9,6,7).foldLeft(List[Int]())(insert)
res25: List[Int] = List(1, 3, 5, 6, 6, 7, 9)
To jedyne rozwiązanie, jakie mogłem wymyślić sam. Ale ten kod jest ledwo czytelny. Zwłaszcza jeśli porównasz to z imperatywną alternatywą. Zastanawiam się, czy ktoś wie o bardziej eleganckim funkcjonalnym rozwiązaniu. Czy może to dowód na to, że siła ekspresji programowania funkcjonalnego ma swoje ograniczenia? – Dennis
Dodałem opcję foldLeft - wygląda całkiem dobrze – dk14
Dzięki. twoja edycja foldleft jest o wiele bardziej wyrazista, ale także znacznie bardziej abstrakcyjna. – eita