Vanessa: Doppelte/Gleiche Werte aus Array heraus filtern

Huhu liebes Forum.
Hab jetzt ne ganze Zeit im Internet gesucht, doch leider nur Anleitungen für PHP und andere Scriptsprachen gefunden..

Ich habe einen einfachen, 1-dimensionalen, Array, der an manchen Stellen die gleichen Werte hat (siehe unten). Nun möchte ich gerne die _gleichen_ Werte löschen, bzw. aus dem String raus nehmen - Frage: geht das?

Die Arrays werden automatisch hinzugefügt und steigen innerhalt von ein paar Tagen über die 500er Grenze, somit wäre ein eigenständiges herauspicken wohl unangebracht.. ^^

Ich hoffe, ihr habt einen Vorschlag für mich..

Hier ein mal ein gaaanz kleiner Codeschnipsel (kein Originalquelltext.. grad selbst geschrieben):

  
var Tag = new Array();  
Tag[0] = "abc";  
Tag[1] = "def";  
Tag[2] = "ghi";  
Tag[3] = "jkl";  
Tag[4] = "mno";  
Tag[5] = "abc";  
Tag[6] = "def";  
Tag[7] = "abc";  

Nun soll nur _ein_ mal 'abc' und auch nur _ein_ mal 'def' ausgegeben werden. Wie kann ich das anstellen? Das ist zu hoch für mich.. =((

Danke für jede Hilfe, lG Vanessa

  1. [...]

    var Tag = new Array();
    Tag[0] = "abc";
    Tag[1] = "def";
    Tag[2] = "ghi";
    Tag[3] = "jkl";
    Tag[4] = "mno";
    Tag[5] = "abc";
    Tag[6] = "def";
    Tag[7] = "abc";

    
    > Nun soll nur \_ein\_ mal 'abc' und auch nur \_ein\_ mal 'def' ausgegeben werden. Wie kann ich das anstellen? Das ist zu hoch für mich.. =((  
    > [...]  
      
    Da hilfst Du Dir am besten mit einem temporären assoziativen Array:  
    ~~~javascript
      
    function unique(ain) {  
      var seen = {}  
      var aout = []  
      
      for (var i = 0; i < ain.length; i++) {  
        var elt = ain[i]  
        if (!seen[elt]) {  
          aout.push(elt)  
          seen[elt] = true  
        }  
      }  
      
      return aout  
    }  
    
    
  2. Hallo Vanessa,

    Nun soll nur _ein_ mal 'abc' und auch nur _ein_ mal 'def' ausgegeben werden. Wie kann ich das anstellen? Das ist zu hoch für mich.. =((

    Für eigene Zwecke habe ich mir eine Funktion unique geschrieben, die das gleiche macht wie Murphy es beschreibt - aber direkt als Funktion jedes Arrays angesprochen werden kann.

    /**  
     * Looks for duplicate entries and creates an array that contains each value only once.  
     * Leaves the original array untouched.  
     *  
     * @return Array without duplicate entries.  
     */  
    if (!Array.prototype.unique) {  
     Array.prototype.unique = function() {  
      var uniqueArray = [];  
      
      for (var i = 0; i < this.length; i++) {  
       var found = false;  
       for (var j = 0; j < uniqueArray.length; j++) {  
        if (uniqueArray[j] == this[i]) {  
         found = true;  
         break;  
        }  
       }  
      
       if (!found) {  
        uniqueArray.push(this[i]);  
       }  
      }  
      
      return uniqueArray;  
     };  
    }
    

    Wenn du diesen Code eingebunden hast kannst du mit
    Tag = Tag.unique();
    dein Array um doppelte Einträge bereinigen.

    Grüße

    Marc Reichelt || http://www.marcreichelt.de/

    --
    panic("Oh boy, that early out of memory?");
            linux-2.2.16/arch/mips/mm/init.c
    Selfcode: ie:{ fl:| br:> va:} ls:< fo:} rl:( n4:( ss:) de:> js:| ch:? sh:| mo:) zu:)
    1. Für eigene Zwecke habe ich mir eine Funktion unique geschrieben, die das gleiche macht wie Murphy es beschreibt - aber direkt als Funktion jedes Arrays angesprochen werden kann.

      Die Funktion, die Du gepostet hast, produziert zwar das gleiche Resultat wie meine, ist aber wesentlich ineffizienter, da sie statt Hashlookups lineare Scans verwendet [1].

      Ob man die Funktion lieber extern oder lieber am Prototypen von Arrays verankert haben möchte ist wohl Geschmackssache. Tauscht man in meiner Funktion 'ain' durch 'this' aus und weist sie Array.prototype.unique zu, so kann man sie auch als Methode verwenden.

      [1] In manchen schlecht programmierten JavaScript-Engines, wie zum Beispiel bei alten IE-Versionen, stimmt das nicht, da hier anscheinend auch Objekteigenschaften in linearen Listen gespeichert sind. In diesem Fall ist meine Lösung aber zumindest genauso schnell wie Deine und trotzdem kürzer ;-)

      1. Hay ihr beide.
        Danke für eure so schnellen Antworten.

        Nur ich bin noch Anfänger im Bereich javaScript.. und deshalb weiß ich nicht genau, wie ich eure Funktionen richtig einbinde..
        Einfach per Funktionsaufruf?

        Naja, das lasse ich mal kurz aussen vor..

        Mir tut sich ein neues Problem auf.. wenn ich überlege, wäre das ausblenden bzw. 'löschen' aller doppelten Einträge nicht _genau_ das, was ich brauche.
        Ich müsste das nur auf eine doppelte Variable beziehen.. also in meinem beispiel z.B. _nur_ 'abc'..

        Naja und das Einbinden der 'neuen' Funktion wäre dann die zweite Sache.. die soll per Verweis vom User aus aktiviert werden..

        Wäre super lieb, wenn mir jemand helfen kann, lG Vanessa :)

        1. [...] Mir tut sich ein neues Problem auf.. wenn ich überlege, wäre das ausblenden bzw. 'löschen' aller doppelten Einträge nicht _genau_ das, was ich brauche.
          Ich müsste das nur auf eine doppelte Variable beziehen.. also in meinem beispiel z.B. _nur_ 'abc'..

          Das geht mit einer kleinen Variation der Funktion:

            
          Array.prototype.uniqueSome = function () {  
            var seen = {}  
            var aout = []  
            
            for (var i = 0; i < arguments.length; i++)  
              seen[arguments[i]] = false  
            
            for (var i = 0; i < this.length; i++) {  
              var elt = this[i]  
              if (seen.hasOwnProperty(elt)) {  
                if (!seen[elt]) {  
                  aout.push(elt)  
                  seen[elt] = true  
                }  
              }  
              else  
                aout.push(elt)  
            }  
            
            return aout  
          };  
          
          

          Naja und das Einbinden der 'neuen' Funktion wäre dann die zweite Sache.. die soll per Verweis vom User aus aktiviert werden [...]

          Nichts leichter als das:

            
          <html>  
          <head>  
            <title>Test</title>  
            <script type="text/javascript"><!--  
              Array.prototype.uniqueSome = [...]  
              var someArray = [ "foo", "bar", "baz", "baz", "boing", "foo", "boing" ];  
            --></script>  
          </head>  
          <body>  
            <h1>Test</h1>  
            <p>  
              <a href="javascript:alert(someArray)">Show Array</a><br>  
              <a href="javascript:someArray=someArray.uniqueSome('foo','bar')">Unique occurences of 'foo' and 'bar'</a>  
            </p>  
          </body>  
          </html>  
          
          
      2. Hallo Murphy,

        Die Funktion, die Du gepostet hast, produziert zwar das gleiche Resultat wie meine, ist aber wesentlich ineffizienter, da sie statt Hashlookups lineare Scans verwendet [1].

        Ja, dein Algorithmus ist in der Tat wesentlich besser. Dann werde ich meinen gleich mal verbessern. :-)

        Ob man die Funktion lieber extern oder lieber am Prototypen von Arrays verankert haben möchte ist wohl Geschmackssache. Tauscht man in meiner Funktion 'ain' durch 'this' aus und weist sie Array.prototype.unique zu, so kann man sie auch als Methode verwenden.

        Ich finde prototyping halt genial (habe es erst vor einigen Tagen zum ersten Mal verwendet und bin begeistert).

        Grüße

        Marc Reichelt || http://www.marcreichelt.de/

        --
        panic("Oh boy, that early out of memory?");
                linux-2.2.16/arch/mips/mm/init.c
        Selfcode: ie:{ fl:| br:> va:} ls:< fo:} rl:( n4:( ss:) de:> js:| ch:? sh:| mo:) zu:)
        1. [...] Ich finde prototyping halt genial (habe es erst vor einigen Tagen zum ersten Mal verwendet und bin begeistert).

          Prinzipiell finde ich das auch gut, aber den Prototypen von Array oder Object zu verändern kann lästige Nebenwirkungen haben, da die hinzugefügten Eigenschaften des Prototypen bei Schleifen der Form 'for (var p in <object>) ...' als Werte von p auftauchen.

          Wenn man nicht nur eigenen JavaScript-Code verwendet, der sich dessen nicht bewusst ist, ist es unter Umständen besser, solche Veränderungen sein zu lassen...

      3. Hallo,

        Die Funktion, die Du gepostet hast, produziert zwar das gleiche Resultat wie meine

        Nicht ganz. Soweit ich das sehe, funktioniert deine nicht, wenn das Array etwas anderes enthält als Strings oder Zahlen. Marcs Funktion dagegen schon, könnte aber noch verbessert werden. Auf Anhieb fällt mir dazu ein:

        if (uniqueArray[j] === this[i]) { // genauen Vergleich benutzen

        oder, falls das überall unterstützt wird, an Stelle der ganzen j-Scheife einfach

        uniqueArray.indexOf(this[i]) abfragen.

        Ohne Gewähr, da nicht getestet*

        Gruß, Don P

        *Bin als gebranntes Kind inzwischen seeehr vorsichtig mit ungetesteten
           Behauptungen, wie augenscheinlich sie auch immer sein mögen...

        1. Die Funktion, die Du gepostet hast, produziert zwar das gleiche Resultat wie meine

          Nicht ganz. Soweit ich das sehe, funktioniert deine nicht, wenn das Array etwas anderes enthält als Strings oder Zahlen. [...]

          Stimmt, das habe ich vergessen zu erwähnen. Trotzdem ist diese Lösung sinnvoll, wenn man, wie der OP, Strings oder Zahlen in dem Array stehen hat.

          Außerdem finde ich, dass JavaScript hier einen Designfehler hat. Der String, in den ein Objekt zum Zwecke der Ausgabe oder Interpolation verwandelt wird, sollte standardmäßig irgendeinen einzigartigen Token, wie zum Beispiel die Speicheradresse des Objektes, enthalten. Abgesehen davon, dass das zum Debuggen ausgesprochen sinnvoll ist, würde meine Lösung dann auch mit anderen Objekten funktionieren ;-)

          1. Hallo Murphy

            Nicht ganz. Soweit ich das sehe, funktioniert deine nicht, wenn das Array etwas anderes enthält als Strings oder Zahlen. [...]

            Stimmt, das habe ich vergessen zu erwähnen. Trotzdem ist diese Lösung sinnvoll, wenn man, wie der OP, Strings oder Zahlen in dem Array stehen hat.

            Außerdem finde ich, dass JavaScript hier einen Designfehler hat. Der String, in den ein Objekt zum Zwecke der Ausgabe oder Interpolation verwandelt wird, sollte standardmäßig irgendeinen einzigartigen Token, wie zum Beispiel die Speicheradresse des Objektes, enthalten.

            Sprich ein Referenzscalar wie in Perl,oder?

            Abgesehen davon, dass das zum Debuggen ausgesprochen sinnvoll ist, würde meine Lösung dann auch mit anderen Objekten funktionieren ;-)

            Also für Funktionen lässt sich dein Algo noch ohne weiteres retten, da das toString() einer Funktion sein Body in Stringform ist. Man müsste nur noch zusätzlich statt true die Funktionsreferenz abspeichern und abtesten um sicherzugehen dass nicht unterschiedliche Funktionen das gleiche Body haben.

            Bei anderen Objekten  wirds schwierig, obj.toString() liefert nur sowas wie "[object Object]" und toSource() gibts leider nur im Mozilla.

            Bliebe nur die Möglichkeit für dumme Objekte entweder eine lineare Liste anzulegen oder im Object selbst ein seen=true attribut zu setzen udn später wieder zu löschen.

            Zum Glück taucht das Problem mit Nummern oder String-Objekten wiederum nicht auf weil toString den primitiven Wert zurückliefert.

            Ciao
             LanX

            1. Hi

              Also für Funktionen lässt sich dein Algo noch ohne weiteres retten, da das toString() einer Funktion sein Body in Stringform ist. Man müsste nur noch zusätzlich statt true die Funktionsreferenz abspeichern und abtesten um sicherzugehen dass nicht unterschiedliche Funktionen das gleiche Body haben.

              kleiner denkfehler, es könnte ja sogar >2 Funktionen in der Liste geben die das gleiche Body haben, also müsste analog zu den Objekten hier ein eigenes Array angelegt werden, das linear durchsucht wird.

              Ciao
               LanX

            2. [...]

              Außerdem finde ich, dass JavaScript hier einen Designfehler hat. Der String, in den ein Objekt zum Zwecke der Ausgabe oder Interpolation verwandelt wird, sollte standardmäßig irgendeinen einzigartigen Token, wie zum Beispiel die Speicheradresse des Objektes, enthalten.

              Sprich ein Referenzscalar wie in Perl,oder?

              Nein, das Äquivalent zu dem was ich meine ist in Perl ein sogenannter Stash.

              Beispiel:

                
              my $reference = { x => 42 }; # reference to an anonymous hash  
              my $stash = "$reference";    # string matching /^HASH\(0x[0-9a-fA-F]+\)$/  
              
              

              $reference ist für mich ein "Referenzskalar". $stash ist einfach nur eine Zeichenkette, die aber das Objekt, welches $reference referenziert, eindeutig identifiziert.

              1. Hallo

                Nein, das Äquivalent zu dem was ich meine ist in Perl ein sogenannter Stash.

                Beispiel:

                my $reference = { x => 42 }; # reference to an anonymous hash
                my $stash = "$reference";    # string matching /^HASH(0x[0-9a-fA-F]+)$/

                  
                OK wir meinen aber das gleiche, nämlich was print \@arr ausgibt!  
                  
                Stash hab ich noch nie gehört, aber man lernt nie aus :)  
                  
                Ciao  
                 LanX
                
    2. Hallo,

      Man muss das Rad nicht immer neu erfinden. Habe für euch mal kurz folgende Funktionen geliehen (es gibt dort noch viele mehr):

        
      // Array.indexOf( value, begin, strict ) - Return index of the first element that matches value  
      Array.prototype.indexOf = function( v, b, s ) {  
       for( var i = +b || 0, l = this.length; i < l; i++ ) {  
        if( this[i]===v || s && this[i]==v ) { return i; }  
       }  
       return -1;  
      };  
        
      // Array.unique( strict ) - Remove duplicate values  
      Array.prototype.unique = function( b ) {  
       var a = [], i, l = this.length;  
       for( i=0; i<l; i++ ) {  
        if( a.indexOf( this[i], 0, b ) < 0 ) { a.push( this[i] ); }  
       }  
       return a;  
      };
      

      Am Besten man fragt jeweils vorher ab z.B. für indexOf()mit

        
      if (!Array.prototype.indexOf){  
      // Hier die Funktion  
      }
      

      Gruß, Don P

      1. Hallo Don,

        Man muss das Rad nicht immer neu erfinden. Habe für euch mal kurz folgende Funktionen geliehen (es gibt dort noch viele mehr):

        Davon wusste ich halt nichts. Ist ja auch egal, wenn man sich die Funktion selbst schreiben kann. Oder?

        // Array.unique( strict ) - Remove duplicate values
        Array.prototype.unique = function( b ) {
        var a = [], i, l = this.length;
        for( i=0; i<l; i++ ) {
          if( a.indexOf( this[i], 0, b ) < 0 ) { a.push( this[i] ); }
        }
        return a;
        };

          
        Deine Funktion unique ist aber genauso langsam wie meine bis vor wenigen Stunden. Murphys Variante ist wirklich wesentlich schneller.  
          
        Insofern: Gut, dass wir das Rad neu erfunden haben. ;-)  
          
          
        Grüße  
          
        Marc Reichelt || <http://www.marcreichelt.de/>  
        
        -- 
        panic("Oh boy, that early out of memory?");  
                linux-2.2.16/arch/mips/mm/init.c  
          
        [Selfcode](http://emmanuel.dammerer.at/selfcode.html): ie:{ fl:| br:> va:} ls:< fo:} rl:( n4:( ss:) de:> js:| ch:? sh:| mo:) zu:)
        
        1. Hallo,

          Davon wusste ich halt nichts. Ist ja auch egal, wenn man sich die Funktion selbst schreiben kann. Oder?

          Ja klar. Das sollte auch kein Vorwurf sein. Selber machen ist immer gut, schließlich lernt man dabei.

          Deine Funktion unique ist aber genauso langsam wie meine bis vor wenigen Stunden. Murphys Variante ist wirklich wesentlich schneller.

          Naja, es ist nicht wirklich meine (nur geliehen ;-), und sie ist viel universeller, arbeitet nicht nur mit Strings und Zahlen wie Murphys Variante, sondern das Array kann alles Mögliche enthalten. So gesehen ist ein Performance-Vergleich etwas unfair, wie der Vergleich von Äpfeln mit Birnen.

          Insofern: Gut, dass wir das Rad neu erfunden haben. ;-)

          Klar doch, wenn du nur Strings im Array hast ist es so allemal besser. Das nächste Mal aber, wenn auch Objekte, null oder sonstwas dabei sind, musst du halt wieder neu anfangen.

          Gruß, Don P