Właśnie przeczytałem, że czas wykonania operacji dołączania dla List
(: +) rośnie liniowo wraz z rozmiarem pliku List
.
Dołączanie do List
wydaje się dość powszechną operacją. Dlaczego idiomatycznym sposobem na to jest przygotowanie komponentów, a następnie odwrócenie listy? Nie może to być również błąd projektu, ponieważ implementacja może zostać zmieniona w dowolnym momencie.
Z mojego punktu widzenia zarówno dodawanie, jak i dodawanie powinno być O (1).
Czy jest to uzasadniony powód?
List[T]
zakłada, że używasz go tak, jak w czysto funkcjonalnym języku - na ogół pracując od głowy z dekonstrukcją i przygotowując.Odpowiedzi:
Rozbuduję trochę mój komentarz. Struktura
List[T]
danych fromscala.collection.immutable
jest zoptymalizowana do działania w taki sposób, aby działała niezmienna lista w czysto funkcjonalnym języku programowania. Ma bardzo krótki czas przygotowania i zakłada się, że będziesz pracować nad głową prawie przez cały swój dostęp.Niezmienne listy mogą mieć bardzo krótkie czasy prepend, ponieważ modelują one swoje połączone listy jako serię „komórek przeciw”. Komórka definiuje pojedynczą wartość i wskaźnik do następnej komórki (klasyczny styl pojedynczo połączonych list):
Kiedy przechodzisz do listy, tak naprawdę tworzysz tylko jedną nową komórkę, a reszta istniejącej listy jest wskazywana:
Ponieważ lista jest niezmienna, możesz to zrobić bez faktycznego kopiowania . Nie ma niebezpieczeństwa zmiany starej listy i spowodowania, że wszystkie wartości na nowej liście staną się nieprawidłowe. Jednak tracisz możliwość posiadania zmiennego wskaźnika na końcu listy jako kompromis.
To bardzo dobrze nadaje się do rekurencyjnej pracy nad listami. Załóżmy, że zdefiniowałeś własną wersję
filter
:Jest to funkcja rekurencyjna, która działa wyłącznie na początku listy i wykorzystuje dopasowanie wzorca za pomocą :: ekstraktora. To jest coś, co często widuje się w językach takich jak Haskell.
Jeśli naprawdę chcesz mieć szybkie dodatki, Scala oferuje wiele zmiennych i niezmiennych struktur danych do wyboru. Po stronie zmiennej możesz zajrzeć
ListBuffer
. Alternatywnie,Vector
odscala.collection.immutable
ma szybki czas dołączania.źródło
else
jest nieskończona pętla? Myślę, że tak powinno byćx::deleteIf(xs)(f)
.head
itail
dostęp z tego rodzaju listą jest bardzo szybki - szybszy niż przy użyciu dowolnej mapy lub tablicy opartej na haszowaniu - jest to doskonały typ dla funkcji rekurencyjnych. To jeden z powodów, dla których listy są podstawowym typem w większości języków funkcjonalnych (np. Haskell lub Scheme)List
s i dołączania / dodawania).