W Mathematica, tworzę pojedynczo związane listy tak:Mathematica „Listy” połączone i wydajność
toLinkedList[x_List] := Fold[pair[#2, #1] &, pair[], Reverse[x]];
fromLinkedList[ll_pair] := List @@ Flatten[ll];
emptyQ[pair[]] := True;
emptyQ[_pair] := False;
Używanie symbolu pair
dla komórek minusy ma tę zaletę Flatten
pracuje bezpiecznie nawet jeżeli wykazy zawierają Mathematica- style List
s, i pozwala zdefiniować niestandardową notację za pomocą MakeExpression
/MakeBoxes
, co czyni wszystko znacznie przyjemniejszym. W celu uniknięcia konieczności wymieszania się z $IterationLimit
, napisałem funkcje do pracy z tymi listami za pomocą pętli While
lub NestWhile
zamiast rekursji. Oczywiście, chciałem zobaczyć, które podejście byłoby szybciej, więc napisałem dwóch kandydatów, więc mogłem oglądać „em walczyć:
nestLength[ll_pair] :=
With[{step = {#[[1, -1]], #[[-1]] + 1} &},
[email protected][step, {ll, 0}, ! [email protected]@# &]];
whileLength[ll_pair] :=
Module[{result = 0, current = ll},
While[! [email protected],
current = current[[2]];
++result];
result];
Wyniki były bardzo dziwne. Testowałem funkcje na połączonych listach o długości 10000, a whileLength
było zazwyczaj o około 50% szybsze, o około 0,035 sekundy do 0,055 sekundy, czyli nestLength
. Jednak czasami whileLength
zajęłoby około ~ 4 sekund. Pomyślałem, że może wystąpić pewne zachowanie związane z buforowaniem, więc zacząłem generować świeże, losowe listy do sprawdzenia, a whileLength
niekoniecznie będzie wolne przy pierwszym uruchomieniu z nową listą; może to zająć kilkadziesiąt razy, aby zobaczyć spowolnienie, ale potem nie powtórzyłoby się (przynajmniej nie dla 200 przebiegów próbowałem z każdą listą).
Co może się dziać?
Dla porównania, funkcja I wykorzystywane do testowania to:
getTimes[f_, n_] :=
With[{ll = [email protected][100, 10000]},
Table[Timing[[email protected]], {n}][[All, 1]]]
EDIT: I zapomniał wspomnieć wersję wcześniej; Mam te wyniki z Mathematica 8.
edytować drugiego: Kiedy czytam Daniel Lichtblau's answer, zdałem sobie sprawę, że moje czasy dla „typowych” przebiegów pominięte wiodącą 0. Jest został naprawiony.
EDYTUJ trzecią: Myślę, że Leonid Shifrin jest poprawna, aby skojarzyć problem z Module
; Mogę dostać ten sam rodzaj zachowania z NestWhile
wersji opartym zastępując With
z Module
:
nestModuleLength[ll_pair] :=
Module[{step = {#[[1, -1]], #[[-1]] + 1} &},
[email protected][step, {ll, 0}, ! [email protected]@# &]];
In[15]:= Select[getTimes[nestModuleLength, 100], # > 3 &]
Out[15]= {3.797}
Developer'PackedArrayQ mogą być istotne –
@Yaroslav Bulatov: Nie mogę zrozumieć, dlaczego pakowane tablice będą miały znaczenia, ponieważ nic nie powinno być pakowane z wyjątkiem początkowego 'List' generowanego przez' RandomInteger ', który jest natychmiast konwertowany na wyrażenie podobne do drzewa. – Pillsy
Czy używasz wersji 7 lub 8? Niezależnie od tego, o ile jest to warte, myślę, że odkryłeś coś w rodzaju błędu lub co najmniej delikatnego miejsca w zachowaniu ewaluacyjnym. –