Beim Erstellen eines JavaScript-Interpreters für eine einfache Sprache habe ich das folgende Problem festgestellt:
Nach dem Parsen erhalten wir ein Array von Indizes, das das Element in einem n-dimensionalen Array angibt, das modifiziert werden soll. Zum Beispiel nach dem Parsen:
%Vor% Wir erhalten ein Array [1, 1, 1]
. Die Sprache, an der ich arbeite, hat keine Variablendefinitionen, daher werden Variablen bei ihrer ersten Verwendung initialisiert. Mein Ziel ist es, dieses n-dimensionale Array so zu erstellen, dass ich es in die Variablentabelle einfügen kann (im obigen Beispiel müssten wir ein 3-dimensionales Array erstellen).
eval()
zu erstellen?
Getestet in Chrome:
%Vor% Dann gibt createNDimArray([3, 2, 5])
ein 3x2x5 Array zurück.
Sie können eine ähnliche rekursive Prozedur verwenden, um auf ein Element zuzugreifen, dessen Index sich in einem Array befindet:
%Vor%Das Setzen eines Elements ist ähnlich und wird dem Leser als Übung überlassen.
Es ist nichts eingebaut, aber es ist ziemlich einfach, eine Funktion zu erstellen, die den Job erledigt:
%Vor%Vielleicht hilft das?
PS -
Ich weiß, dass dies mehr Anstrengung als nötig erscheinen mag. Aber leider sind JavaScript-Arrays nicht wirklich "Arrays" (wenn man unter "Array" einen zusammenhängenden, indizierten, unveränderlichen Speicherblock versteht). Sie sind mehr wie "Karten" in den meisten Sprachen. Es ist also ein gewisser Aufwand nötig, um sie zu erstellen. Die meisten Sprachen haben kein Problem mehrdimensionale Arrays zu erstellen, da sie nur eine einfache Multiplikation gefolgt von einem malloc()
ausführen. Aber mit JavaScript müssen Sie rekursiv Ihre Arrays generieren, wenn Sie sie vorkonstruiert haben wollen. Es ist ein Schmerz, aber es zeigt den Aufwand für den Dolmetscher.
Geh Figur.
Verwenden einer modifizierten Version von jfabrizio der Lösung:
%Vor%Nutzungen:
%Vor% Ich fand das ein bisschen schneller. Ich könnte sagen, dass es der schnellste Weg wäre, ein N-dimensionales Array in Javascript zu generieren. Dieses Refactoring oben hatte einige gute Geschwindigkeitssteigerungen. Aber die beste Geschwindigkeitszunahme kam natürlich nicht durch das Vorfüllen. Diese Version füllt das Array nicht voraus. Es gibt nur ein vollständig erstelltes N-dimensionales Array von Ns-Längen zurück, wobei die letzte Ebene nur ein leeres Array ist. Ich würde hoffen, dass arr[x][y][z]?arr[x][y][z]:null
ausreichend ist, wenn Sie wirklich den Wert null
benötigen. Es ist für meine Zwecke. :)
Wenn Sie vorfüllen müssen, verwenden Sie seine Originalversion.
Und wenn Sie sich nicht wirklich dafür interessieren, was ich getan habe; dann hör auf zu lesen.
Willst du mehr Geek reden? Ein bisschen etwas über Rekursion für diejenigen, die da draußen lernen. Okay, hier sind die Taktiken. Berücksichtigen Sie bei der Tiefenrekursion das letzte Level. Es ist der größte Teil der Arbeit erledigt. In diesem Fall ist es buchstäblich die N-te Dimension. Das ist Ihre "Nutzlast", der Rest ist Logistik. In der Funktion von jfab, wenn dimensions.length
zu 1
gelangt, wird seine letzte Dimension in der N-ten Dimension angezeigt und die Nutzlast wird ausgeführt. Welches ist das Array von Nullen zu erstellen, oder in meinem Fall ein leeres Array. Da die Rekursion so tief ist, ist jede Dimension ein Faktor der letzten. Bis Sie die N-te Dimension erreicht haben, werden Sie viele Funktionsaufrufe haben und die Logistik wird für den Computer mühsam. Und in der N-ten Dimension werden Sie Ihre Basisrekursionsfunktion ( createNDimArray
in unserem Fall) häufiger für die Nutzlast nennen als für die Logistik. Nun, wie in der ursprünglichen Lösung von jfab, ist es in der Regel eine gute Sache, die Ausführung der Nutzlast als erstes in die Rekursion (wenn möglich) zu tun, besonders wenn es einfach ist. Hier wird die Nutzlast zu einem Gebäude des endgültigen 2D-Arrays (anstatt nur eines 1D-Arrays, indem einfach nur ein new Array()
zurückgegeben wird). Dann muss die übermäßige Anzahl von Funktionsaufrufen nun nicht auf dieser Ebene stattfinden. Nun, natürlich, wenn Sie das Array vorab füllen wollen, dann hilft diese Abkürzung nicht immer. Aber mehr auf den Punkt, würde das Vorausfüllen des Arrays die geeignete Nutzlast sein. Durch den nicht Besuch jedes Elements in der N-ten Dimension haben wir es effektiv entfernt. Auf diese Weise gibt es eine Ebene weniger Funktionsaufrufe und grundsätzlich wird die Nutzlast der N-ten Dimension tatsächlich auf der N-1-ten Dimension ausgeführt. Und wir rufen die rekursive Funktion nie wieder auf, nur um das new Array()
zu liefern. Leider sieht der Aufruf von new Array(x)
(im Allgemeinen) das nicht so. Die Ausführungszeit erhöht sich mit einem größeren x
. Das ist eigentlich immer noch jeden Gegenstand in der N-ten Dimension zu besuchen, aber jetzt machen wir es nur einmal und mit nativem Code und eingewickelt in eine enge und leichte Schleife. Jetzt benötigen wir, dass createNDimArray
nur mit N & gt; 1, dh nie zum Erstellen von 1D-Arrays verwendet. Theoretisch könnte man ein größeres N benötigen und am Ende noch mehr Dimensionen ausrollen. Im Grunde liest die Zeile mit if ( dimensions.length < 3 )
etwas wie < 4
oder < 5
und du müsstest viel mehr for
-Schleifen um die eine Schleife wickeln, die dort sind, und sie alle würden ihre eigene Menge% co_de brauchen % s --- also bin ich mir nicht sicher, wie effizient alles sein könnte, da Sie exzessiven Funktionsaufruf und Stapelplatz / Manipulation mit einer ähnlichen Idee handeln, aber in eingebetteten var
loops --- Aber ich nehme an, dass es beschleunigen könnte Ups einige Umgebungen, wenn Sie wissen, dass N immer über einer bestimmten Ebene oder wenn es nur für die endgültigen Dimensionen ist. Wie hier habe ich es für die letzten zwei Dimensionen getan. Aber wenn Sie zu viel ausrollen, dann ist Ihre Nutzlast selbst ein Bär. Nur Tests werden zeigen, ob es das wert ist. Es scheint, dass der Stack-Bereich begrenzt ist, und ich denke, ich erinnere mich daran, dass ich größere Arrays mit mehr Abrollen herstellen konnte. Wie groß Sie ein Array erstellen können, ist begrenzt. Und Rekursionslösungen, die sich für jedes Element auf der N-ten Ebene aufrufen, hatten die niedrigste Grenze, wenn ich ... mich richtig erinnere ... viel niedriger.
Der nächste Teil bei der Überarbeitung seiner Lösung ist nur die Logistik, es war nur ein einfacher Refaktor, um übermäßige Blöcke und Code loszuwerden. Mach mit, dass alle for
zusammenarbeiten und das ist es. Da Sie ein var
benötigen, um zurückzukehren, nachdem das Looping beendet ist, könnte auch Ihr arr
zuerst auf einer Zeile arbeiten und glücklicherweise haben drei der vier var
s dieselbe Initialisierung. Denken Sie daran, dass JavaScript den Code bei der Verknüpfung mit var
optimieren kann, wenn dies möglich ist. Dies macht auch kleineren Code.
PT
Tags und Links javascript arrays