JavaScript; n-dimensionale Array-Erstellung

8

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).

Die kurze Frage:

Gibt es eine Möglichkeit, ein n-dimensionales Array in JavaScript ohne mit eval() zu erstellen?     
Chris 25.09.2012, 18:04
quelle

6 Antworten

11

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.

    
Barmar 25.09.2012, 18:18
quelle
5

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.

    
Pete 25.09.2012 18:15
quelle
1

Zum Erstellen eines n-dimensionalen Arrays:

%Vor%     
jfabrizio 03.05.2013 11:32
quelle
0

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

    
Pimp Trizkit 24.09.2015 10:55
quelle
0

Eine weitere Version von createNDimArray mit map , apply und bind functions:

%Vor%     
madox2 20.12.2015 11:28
quelle
0

Das Erstellen eines ND-Arrays erfordert das Klonen verschachtelter ND-Arrays. Dementsprechend benötigen Sie eine richtige Array.prototype.clone() -Methode und der Rest ist einfach. Nach meinem Wissen ist das Folgende der einfachste und effizienteste Weg in JS.

%Vor%
    
Redu 28.05.2016 07:24
quelle

Tags und Links