LanX!: Array in ein anderes Array kopieren ohne ein neues zu erzeugen

Hi

ich habe keine Hoffnung dass es geht, aber vielleicht belehrt ihr mich ja eines besseren.

JS kennt keine List-Assignments von Arrays wie in Perl, also

  
$a=[1,2,3];  
$b=[4,5,6];  
$c=$a;  
@$a=@$b;  
if ($c == $a) { print "Klappt, keine neue Referenz, \$a zeigt auf das alte Array"}  

Ich habe mir dazu slice angeschaut, aber dort müsste ich die neuen Elemente einzeln auflisten, ich kann b nicht zu einer Liste abflachen (wie mit @$b in Perl)

a.splice(0,a.length,4,5,6)

Auch concat oder slice helfen mir nicht weiter, weil hierbei neues Arrays erzeugt werden, d.h. die alten Referenzen nicht mehr stimmen:

a=[1,2,3];  
b=[4,5,6];  
c=a=[];  
a=b.slice(0);  
if (c != a) { alert( "klappt nicht" ) }  

Hat jemand vielleicht ne gute Idee wie man performant umkopieren kann, ohne eine explizite Schleife dafür schreiben zu müssen?

Grüße
  Rolf

  1. [latex]Mae  govannen![/latex]

    Hat jemand vielleicht ne gute Idee wie man performant umkopieren kann, ohne eine explizite Schleife dafür schreiben zu müssen?

    Vielleicht kannst du das Array  via reduce zusammenfassen (siehe „flatten“ Beispiel). Wobei ich nicht ganz verstehe, was du im Endeffekt genau erreichen willst.
    Wie sollen die Variablen a,b,c nach der Operation aussehen? Im Moment klingt das Ganze nach einem suboptimalem Ansatz

    Stur lächeln und winken, Männer!
    Kai

    --
    Dank Hixies Idiotenbande geschieht grade eben wieder ein Umdenken
    in Richtung "Mess up the Web".(suit)
    SelfHTML-Forum-Stylesheet
    1. Wie sollen die Variablen a,b,c nach der Operation aussehen? Im Moment klingt das Ganze nach einem suboptimalem Ansatz

      c soll weiterhin ein alias von a sein.

      1. Lieber LanX!,

        c soll weiterhin ein alias von a sein.

        das ist das einzige, was mir klar ist. Welche Rolle spielt b in Deinem Beispiel?

        Liebe Grüße,

        Felix Riesterer.

        --
        ie:% br:> fl:| va:) ls:[ fo:) rl:| n4:? de:> ss:| ch:? js:) mo:} zu:)
        1. Hi Felix,

          das ist das einzige, was mir klar ist. Welche Rolle spielt b in Deinem Beispiel?

          das Array b enthält die Daten die in a rein sollen, ohne dass a eine neue Speicherstelle erhält.

          Ciao
            Rolf

          PS: eventuell verwirrt dich ja der Typo im OP?

          1. Lieber LanX!,

            ohne dass a eine neue Speicherstelle erhält.

            was willst Du mir damit sagen? Ich verstehe wirklich nicht, wie Du denkst!

            Liebe Grüße,

            Felix Riesterer.

            --
            ie:% br:> fl:| va:) ls:[ fo:) rl:| n4:? de:> ss:| ch:? js:) mo:} zu:)
            1. Hi Felix

              was willst Du mir damit sagen? Ich verstehe wirklich nicht, wie Du denkst!

              OK, vielleicht ist es mir einfach zu klar weil ich Perler bin, wo Referenzen explizite Datentypen sind, und das nicht so wischi waschi in den Innereien versteckt wird.

              Kennst du den Unterschied zwischen

                
              a=[];  
              b=[1,2,3];  
              a=b;  
              
              

              und

                
              a=[];  
              b=[1,2,3];  
              a=b.slice(0);  
              
              

              und

                
              a=[];  
              b=[1,2,3];  
              for (i in b) {a[i]=b[i]};  
              
              

              ???

              Und weißt du auch was == bei Objekten abprüft???

              Ciao
                Rolf

              1. Lieber LanX!,

                a=[];

                b=[1,2,3];
                a=b;

                  
                hier wird zuerst eine (globale) Variable "a" initialisiert und eine Referenz auf eine Objektinstanz des Prototypen "Array" als Wert zugewiesen. Bei "b" verhält es sich genauso, nur mit dem Unterschied, dass das Objekt, auf welches "b" verweist, noch drei Eigenschaften erhält, nämlich die drei Felder mit den Zahlenwerten 1-3.  
                  
                Anschließend wird der Wert der Variablen "a" komplett überschrieben, indem eine (zweite) Referenz auf das Objekt, welches in der Variablen "b" bereits referenziert wird, in "a" abgelegt wird. Somit ist die Variablen "a" zu einem Alias für die Variablen "b" geworden. Das ursprünglich in "a" referenzierte Objekt wandert in den Mülleimer und wird vom garbage collector aufgefressen.  
                  
                War das so richtig?  
                  
                
                > ~~~javascript
                
                a=[];  
                
                > b=[1,2,3];  
                > a=b.slice(0);
                
                

                In den ersten beiden Zeilen gilt das bereits oben beschriebene Vorgehen. Anschließend wird eine Methode des Array-Objektes angewandt, um das Array-Objekt in "a" zu verändern. Die Methode "slice" extrahiert die Elemente des Arrays "b", beginnend mit dem bei Index "0" (also das erste) und endend mit dem letzten. Da Du keinen zweiten Parameter bei slice angegeben hast, wird der wie ein false oder "-1" gewertet, was soviel bedeutet, wie "bis einschließlich dem letzten Element".

                Dadurch steht in "a" keine Referenz auf ein und dasselbe Objekt wie in "b", sondern eine Referenz auf die anfangs initialisierte Instanz des Prototypen "Array". In diesem Beispiel gibt es also zwei unterschiedliche Array-Objekte.

                Anzumerken ist noch, dass die Werte, die in "a" über splice eingefügt wurden innerhalb von JavaScript keine Referenzen auf die jeweiligen "Original-Werte" in "b" sind, da Integer-Zahlen im Regelfall nicht als neue "vollständige" Objekte behandelt werden, sondern als primitive Datentypen. Hier wurden also tatsächlich Kopien der Werte angefertigt. In anderen Worten: In "a" stehen echte Zahlenwerte, keine Referenzen auf die entsprechenden Felder in "b".

                Oder habe ich das falsch interpretiert?

                a=[];

                b=[1,2,3];
                for (i in b) {a[i]=b[i]};

                  
                Auch hier gilt in den ersten beiden Zeilen das oben beschriebene Vorgehen. Anschließend wird durch eine For-Schleife im Array "a" ein Wert eingetragen, der dem in Array "b" entspricht. Allerdings bin ich mir nicht sicher, ob auch hier nur Kopien der Integer-Werte erstellt werden, oder ob a[i] kein primitiver Datentyp ist, sodass a[i] eine Referenz auf b[i] darstellt. Ich vermute aber ganz stark ersteres, also auch wieder echte Zahlenwerte, keine Referenzen auf die entsprechenden Felder in "b".  
                  
                
                > Und weißt du auch was `==`{:.language-javascript} bei Objekten abprüft???  
                  
                Ist Deine Fragezeichen-Taste kaputt?  
                  
                Der `==`{:.language-javascript} Operator prüft nur, ob der Wert als gleich \_interpretiert\_ werden kann. Eine eventuelle Typenumwandlung wird intern automatisch vorgenommen. Deshalb muss man in Fällen wie `0 == false`{:.language-javascript} wissen, dass eine Integer-Zahl mit dem Wert null auch als ein Boolsches "falsch" verstanden werden kann. Will man hier darauf prüfen, ob auch der Datentyp identisch ist, braucht es den `===`{:.language-javascript} Operator.  
                  
                Als "Perler" magst Du vielleicht noch prüfen können, ob Du es mit dem Objekt selbst, oder nur einer Referenz auf es selbst zu tun hast, in JavaScript ist das so nicht möglich. Dazu ist JS zu dynamisch - und das ist auch gut so.  
                  
                Liebe Grüße,  
                  
                Felix Riesterer.
                
                -- 
                ie:% br:> fl:| va:) ls:[ fo:) rl:| n4:? de:> ss:| ch:? js:) mo:} zu:)
                
                1. Lieber Felix

                  War das so richtig?

                  Ja! Und um es vorweg zu nehmen in allen 3 Fällen enthält das Array a die primitiven "number" 1,2,3.

                  a=[];

                  b=[1,2,3];
                  a=b.slice(0);

                    
                  
                  > Dadurch steht in "a" keine Referenz auf ein und dasselbe Objekt wie in "b", sondern eine Referenz auf die anfangs initialisierte Instanz des Prototypen "Array". In diesem Beispiel gibt es also zwei unterschiedliche Array-Objekte.  
                    
                  Nein das ist falsch, slice erstellt ein neues Objekt das a zugewiesen wird.  
                    
                  Deswegen ergibt  
                    
                  ~~~javascript
                    
                  c=a=[];  
                  b=[1,2,3];  
                  a=b.slice(0);  
                  alert(c==a);  
                  
                  

                  false.

                  a=[];

                  b=[1,2,3];
                  for (i in b) {a[i]=b[i]};

                    
                  und jetzt ergibt  
                    
                  ~~~javascript
                    
                  c=a=[];  
                  b=[1,2,3];  
                  for (i in b) {a[i]=b[i]};  
                  alert(c==a)  
                  
                  

                  true

                  Und darum ging es mir.

                  Ist Deine Fragezeichen-Taste kaputt?

                  Nein, aber ich verstehe nicht was du nicht verstehst, meine Codebeispiele waren ziemlich explizit.

                  Der == Operator prüft nur, ob der Wert als gleich _interpretiert_ werden kann. Eine eventuelle Typenumwandlung wird intern automatisch vorgenommen.

                  Es gibt keine Typumwandlung weil beide Seiten vom Typ "object" sind, es wir geschaut ob das gleiche Objekt referenziert wird.

                  Als "Perler" magst Du vielleicht noch prüfen können, ob Du es mit dem Objekt selbst, oder nur einer Referenz auf es selbst zu tun hast,

                  Keine Ahnung was du mit dem "Objekt selbst" meinst. Das Model ist ziemlich ähnlich, Objekte sind in Perl Scalare mit Referenzen als Inhalt.

                  Könntest du mir Beispielcode geben?

                  in JavaScript ist das so nicht möglich. Dazu ist JS zu dynamisch - und das ist auch gut so.

                  Es gibt sehr wenig was JS kann und nicht auf Perl abgebildet werden kann.

                  Bei Interesse:

                  "Perl vs JS" (Deutscher Perl Workshop)

                  :)

                  Ciao
                    Rolf

                  1. Hi

                    Als "Perler" magst Du vielleicht noch prüfen können, ob Du es mit dem Objekt selbst, oder nur einer Referenz auf es selbst zu tun hast,

                    Keine Ahnung was du mit dem "Objekt selbst" meinst. Das Model ist ziemlich ähnlich, Objekte sind in Perl Scalare mit Referenzen als Inhalt.

                    Könntest du mir Beispielcode geben?

                    kommt da noch was?

                    Ciao
                      Rolf

  2. Sorry 2 Typos:

    Ich habe mir dazu slice angeschaut, aber dort müsste ich die neuen

    "splice" nicht "slice"

    »» c=a=[];  
    
    

    murks, sollte

    c=a;

    heißen.

    Und hier ein übler workaround um es doch hinzukriegen:

      
    Array.prototype.splice.apply(a,[0,a.length].concat(b))  
    
    

    cheers
     Rolf

    1. Hi

      Array.prototype.splice.apply(a,[0,a.length].concat(b))

        
      kompakter :)  
        
      ~~~javascript
        
      a.length=0;  
      a.push.apply(a,b)  
      
      

      ciao
        Rolf