Array.push () wenn nicht vorhanden?

247

Wie kann ich in ein Array pushen, wenn keiner der Werte vorhanden ist? Hier ist mein Array:

[
    { name: "tom", text: "tasty" },
    { name: "tom", text: "tasty" },
    { name: "tom", text: "tasty" },
    { name: "tom", text: "tasty" },
    { name: "tom", text: "tasty" }
]

Wenn ich versucht habe, mit oder name: "tom"oder erneut in das Array zu pushen text: "tasty", möchte ich nicht, dass etwas passiert ... aber wenn keines davon vorhanden ist, möchte ich, dass es passiert.push()

Wie kann ich das machen?

Tarnfeld
quelle
5
Verwenden Sie ein Wörterbuch (Hash / Baum) anstelle eines Arrays.
Thomas Eding
Sind alle diese in Javascript verfügbar?
Rahul
3
benutze ein Set
Drax
1
Set funktioniert nicht mit einer Reihe von Objekten
rffaguiar

Antworten:

114

Sie können den Array-Prototyp mit einer benutzerdefinierten Methode erweitern:

// check if an element exists in array using a comparer function
// comparer : function(currentElement)
Array.prototype.inArray = function(comparer) { 
    for(var i=0; i < this.length; i++) { 
        if(comparer(this[i])) return true; 
    }
    return false; 
}; 

// adds an element to the array if it does not already exist using a comparer 
// function
Array.prototype.pushIfNotExist = function(element, comparer) { 
    if (!this.inArray(comparer)) {
        this.push(element);
    }
}; 

var array = [{ name: "tom", text: "tasty" }];
var element = { name: "tom", text: "tasty" };
array.pushIfNotExist(element, function(e) { 
    return e.name === element.name && e.text === element.text; 
});
Darin Dimitrov
quelle
5
Ich denke, Ihr Camparer (Komparator?) Sollte zwei Argumente verwenden. Dies würde den Fall vereinfachen, wenn der Mehrwert inline ist und nicht in einer Variablen, auf die Sie in Ihrer Funktion zugreifen können. array.pushIfNotExist ({Name: "tom", Text: "lecker"}, Funktion (a, b) {return a.name === b.name && a.text === b.text;});
Vincent Robert
26
Ich frage mich, warum dies nicht in der Sprache beheimatet ist - vergessen Sie, wie es implementiert ist -, dass die Idee, nur dann hinzuzufügen, wenn sie eindeutig ist, so grundlegend ist, dass angenommen wird, dass sie existiert.
JustSteve
9
Es ist besser, den Array-Prototyp mit der JavaScript 1.6-Methode IndexOf anstelle Ihres inArray zu erweitern.
Eugene Gluhotorenko
7
Array.findIndex()ist eine integrierte JS-Funktion, die dasselbe erreicht wie Ihr Code.
4
Das direkte Erweitern eingebauter Objekte ist eine schlechte Praxis.
Slava Fomin II
429

Für ein Array von Zeichenfolgen (aber nicht für ein Array von Objekten) können Sie durch Aufrufen überprüfen, ob ein Element vorhanden ist, .indexOf()und ob dies nicht der Fall ist , wird das Element in das Array verschoben:

var newItem = "NEW_ITEM_TO_ARRAY";
var array = ["OLD_ITEM_1", "OLD_ITEM_2"];

array.indexOf(newItem) === -1 ? array.push(newItem) : console.log("This item already exists");

console.log(array)

Jiří Zahálka
quelle
50
Ich bin mir nicht sicher, warum dies nicht als korrekt gekennzeichnet ist. Es verwendet keine externen Geräte, erfordert keine Erstellung einer Erweiterung und ist kinderleicht. Perfekte Antwort auf ops Frage.
Pimbrouwers
39
In der ersten Frage sind die Werte des Arrays Objekte, keine Zeichenfolgen (und diese Lösung funktioniert nicht so, als wären Werte Objekte).
Simon Hi
12
@EmilPedersen - nicht wirklich. Versuchen Sie es if (a.indexOf({ name: "tom", text: "tasty" })!=-1) a.push({ name: "tom", text: "tasty" })zweimal. Es wird zweimal ein "ähnliches" Objekt hinzugefügt.
Commonpike
18
Diese Antwort sollte entfernt werden, da sie objektiv falsch ist, aber dennoch die höchste Anzahl an positiven Stimmen anzieht.
Nikola
2
Dies ist keine richtige Antwort, warum wird akzeptiert? Es funktioniert nur für Js-Arrays, nicht für Objekte innerhalb von Arrays.
Digitai
100

Es ist ziemlich einfach, die Array.findIndexFunktion zu verwenden, die eine Funktion als Argument verwendet:

var a = [{name:"bull", text: "sour"},
    { name: "tom", text: "tasty" },
    { name: "tom", text: "tasty" }
]
var index = a.findIndex(x => x.name=="bob")
// here you can check specific property for an object whether it exist in your array or not

if (index === -1){
    a.push({your_object});
}
else console.log("object already exists")
Ashish Yadav
quelle
8
DAS ist die Antwort Jungs !!
Jafed
2
am relevantesten, um ein Element in das Array hinzuzufügen, wenn es nicht vorhanden ist
akshay bagade
1
Danke, habe überall danach gesucht.
dt192
41

http://api.jquery.com/jQuery.unique/

var cleanArray = $.unique(clutteredArray);

Vielleicht interessiert Sie auch makeArray

Im vorherigen Beispiel sollten Sie vor dem Drücken überprüfen, ob es vorhanden ist. Ich sehe im Nachhinein auch, dass Sie es als Teil des Prototyps deklarieren können (ich denke, das ist auch als Klassenerweiterung bekannt), also keine große Verbesserung unten.

Außer ich bin mir nicht sicher, ob indexOf eine schnellere Route ist als inArray? wahrscheinlich.

Array.prototype.pushUnique = function (item){
    if(this.indexOf(item) == -1) {
    //if(jQuery.inArray(item, this) == -1) {
        this.push(item);
        return true;
    }
    return false;
}
MistereeDevlord
quelle
22
Über den jQuery-Link: Note that this only works on arrays of DOM elements, not strings or numbers.Außerdem funktioniert indexOf in IE8 nicht :(
dmathisen
Sie könnten lodash _.indexOf verwenden, das in IE8
LTroya
25

Verwenden Sie genau aus diesen Gründen eine js-Bibliothek wie underscore.js . Verwendung: Vereinigung: Berechnet die Vereinigung der übergebenen Arrays: Die Liste der eindeutigen Elemente in der Reihenfolge, die in einem oder mehreren der Arrays vorhanden sind.

_.union([1, 2, 3], [101, 2, 1, 10], [2, 1]);
=> [1, 2, 3, 101, 10]
Ronen Rabinovici
quelle
8
Beachten Sie, dass dies ein neues Array zurückgibt und nicht auf ein vorhandenes Array übertragen wird.
Ilovett
4
IMHO gibt es wirklich keine Notwendigkeit, ein Framework
einzubringen
24

So was?

var item = "Hello World";
var array = [];
if (array.indexOf(item) === -1) array.push(item);

Mit Objekt

var item = {name: "tom", text: "tasty"}
var array = [{}]
if (!array.find(o => o.name === 'tom' && o.text === 'tasty'))
    array.push(item)
Ronnie Royston
quelle
4
array.findist eine schlechte Idee, weil es das gesamte Array durchsucht. Verwenden Sie findIndexdiese Option , die nur bis zum ersten Auftreten sucht.
3
@ K48 laut diesem: stackoverflow.com/a/33759573/5227365 "find" stoppt, nachdem es den Artikel gefunden hat
Pascal
19

Ich weiß, dass dies eine sehr alte Frage ist, aber wenn Sie ES6 verwenden, können Sie eine sehr kleine Version verwenden:

[1,2,3].filter(f => f !== 3).concat([3])

Sehr einfach, fügen Sie zuerst einen Filter hinzu, der das Element entfernt - falls es bereits vorhanden ist, und fügen Sie es dann über einen Concat hinzu.

Hier ist ein realistischeres Beispiel:

const myArray = ['hello', 'world']
const newArrayItem

myArray.filter(f => f !== newArrayItem).concat([newArrayItem])

Wenn Ihr Array Objekte enthält, können Sie die Filterfunktion folgendermaßen anpassen:

someArray.filter(f => f.some(s => s.id === myId)).concat([{ id: myId }])
Michael J. Zoidl
quelle
3
Eine ziemlich elegante Lösung hier. Vielen Dank!
Jonathan Picazo
18

Dynamisch drücken

var a = [
  {name:"bull", text: "sour"},
  {name: "tom", text: "tasty" },
  {name: "Jerry", text: "tasty" }
]

function addItem(item) {
  var index = a.findIndex(x => x.name == item.name)
  if (index === -1) {
    a.push(item);
  }else {
    console.log("object already exists")
  }
}

var item = {name:"bull", text: "sour"};
addItem(item);

In einfacher Methode

var item = {name:"bull", text: "sour"};
a.findIndex(x => x.name == item.name) == -1 ? a.push(item) : console.log("object already exists")

Wenn das Array nur primitive Typen / einfaches Array enthält

var b = [1, 7, 8, 4, 3];
var newItem = 6;
b.indexOf(newItem) === -1 && b.push(newItem);
Gopala raja naika
quelle
2
Gesundheit für Ihre Hände. Einfache und schöne Lösung @Gopala raja naika
Nasimba
11

Ich würde vorschlagen, dass Sie ein Set verwenden ,

Sets erlauben nur eindeutige Einträge, wodurch Ihr Problem automatisch gelöst wird.

Sets können wie folgt deklariert werden:

const baz = new Set(["Foo","Bar"])
Michael McQuade
quelle
Vielen Dank für den Hinweis auf @Michael. Gute Lösung, wenn wir mit minimalem Aufwand unterschiedliche Daten verwalten möchten. FWIW, es ist wichtig zu beachten, dass die Array-Leistung besser ist, da weniger CPU erforderlich ist, um das Element bei Bedarf abzurufen.
Ben
Die Frage fragt nach Array.push, also Set.addist das Äquivalent dazu.
Bryc
9

Einfacher Code: Wenn 'indexOf' '-1' zurückgibt, bedeutet dies, dass sich das Element nicht im Array befindet, und die Bedingung '=== -1' ruft true / false ab.

Der Operator '&&' bedeutet 'und'. Wenn also die erste Bedingung erfüllt ist, verschieben wir sie in das Array.

array.indexOf(newItem) === -1 && array.push(newItem);
Eric Valero
quelle
@ D.Lawrence Ja, jetzt viel besser.
Eric Valero
Es gibt andere akzeptierte Antworten, die die Frage des OP stellen, und sie wurden vor einiger Zeit veröffentlicht. Wenn Sie eine Antwort veröffentlichen, lesen Sie: Wie schreibe ich eine gute Antwort? Bitte stellen Sie sicher, dass Sie entweder eine neue Lösung oder eine wesentlich bessere Erklärung hinzufügen, insbesondere wenn Sie ältere Fragen beantworten.
help-info.de
4

Ich bin mir nicht sicher über die Geschwindigkeit, aber stringification+ indexOfist ein einfacher Ansatz. Beginnen Sie damit, Ihr Array in einen String umzuwandeln:

let strMyArray = JSON.stringify(myArray);

Dann können Sie für eine Reihe von Attribut-Wert-Paaren Folgendes verwenden:

if (strMyArray.indexOf('"name":"tom"') === -1 && strMyArray.indexOf('"text":"tasty"') === -1) {
   myArray.push({ name: "tom", text: "tasty" });
}

Das Finden eines ganzen Objekts ist einfacher:

if (strMyArray.indexOf(JSON.stringify(objAddMe) === -1) { 
   myArray.push(objAddMe);
}
Moshefnord
quelle
3

Falls Sie etwas Einfaches benötigen, ohne den Array-Prototyp erweitern zu wollen:

// Example array
var array = [{id: 1}, {id: 2}, {id: 3}];

function pushIfNew(obj) {
  for (var i = 0; i < array.length; i++) {
    if (array[i].id === obj.id) { // modify whatever property you need
      return;
    }
  }
  array.push(obj);
}
docta_faustus
quelle
3

Für den Fall, dass jemand weniger komplizierte Anforderungen hat, hier meine Anpassung der Antwort für ein einfaches String-Array:

Array.prototype.pushIfNotExist = function(val) {
    if (typeof(val) == 'undefined' || val == '') { return; }
    val = $.trim(val);
    if ($.inArray(val, this) == -1) {
        this.push(val);
    }
};

Update: Ersetzt indexOf und trimmt durch jQuery-Alternativen für die IE8-Kompatibilität

Des Teufels Anwalt
quelle
Es ist eine schöne Lösung, aber warum Trimm verwenden?
Dejan Dozet
2

Ich habe Map und Reduce verwendet, um dies zu tun, wenn Sie nach einer bestimmten Eigenschaft eines Objekts suchen möchten. Dies ist nützlich, da die direkte Objektgleichheit häufig fehlschlägt.

var newItem = {'unique_id': 123};
var searchList = [{'unique_id' : 123}, {'unique_id' : 456}];

hasDuplicate = searchList
   .map(function(e){return e.unique_id== newItem.unique_id})
   .reduce(function(pre, cur) {return pre || cur});

if (hasDuplicate) {
   searchList.push(newItem);
} else {
   console.log("Duplicate Item");
}
Adrian Smith
quelle
2

Kurzes Beispiel:

if (typeof(arr[key]) === "undefined") {
  arr.push(key);
}
GigolNet Guigolachvili
quelle
1
Nicht richtig. Wir sind nicht daran interessiert, die Taste zu drücken, wir möchten ein Name-Wert-Paar drücken, aber nur, wenn es noch nicht existiert.
Stefan
2

a ist das Array von Objekten, die Sie haben

a.findIndex(x => x.property=="WhateverPropertyYouWantToMatch") <0 ? 
a.push(objectYouWantToPush) : console.log("response if object exists");
Julio Peguero
quelle
1

Sie können die findIndex-Methode mit einer Rückruffunktion und ihrem "this" -Parameter verwenden.

Hinweis: Alte Browser kennen findIndex nicht, aber eine Polyfüllung ist verfügbar.

Beispielcode (achten Sie darauf, dass in der ursprünglichen Frage ein neues Objekt nur dann gepusht wird, wenn sich keine seiner Daten in zuvor geposteten Objekten befindet):

var a=[{name:"tom", text:"tasty"}], b;
var magic=function(e) {
    return ((e.name == this.name) || (e.text == this.text));
};

b={name:"tom", text:"tasty"};
if (a.findIndex(magic,b) == -1)
    a.push(b); // nothing done
b={name:"tom", text:"ugly"};
if (a.findIndex(magic,b) == -1)
    a.push(b); // nothing done
b={name:"bob", text:"tasty"};
if (a.findIndex(magic,b) == -1)
    a.push(b); // nothing done
b={name:"bob", text:"ugly"};
if (a.findIndex(magic,b) == -1)
    a.push(b); // b is pushed into a
Simon Hi
quelle
1

Ich denke, ich bin zu spät, um hier zu antworten, aber das ist es, was ich mir schließlich für einen Mail-Manager ausgedacht habe, den ich geschrieben habe. Funktioniert das ist alles was ich brauche.

window.ListManager = [];
$('#add').click(function(){
//Your Functionality
  let data =Math.floor(Math.random() * 5) + 1 
  
  if (window.ListManager.includes(data)){
      console.log("data exists in list")
  }else{
       window.ListManager.push(data);
  }
  
  
  $('#result').text(window.ListManager);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<h1>Unique List</h1>

<p id="result"></p>
<button id="add">Add to List</button>

TheeCodeDragon
quelle
0

Dies funktioniert für einen Objektvergleich. In einigen Fällen müssen Sie möglicherweise viele Felder vergleichen. Schleifen Sie einfach das Array und rufen Sie diese Funktion mit vorhandenen und neuen Elementen auf.

 var objectsEqual = function (object1, object2) {
        if(!object1 || !object2)
            return false;
        var result = true;
        var arrayObj1 = _.keys(object1);
        var currentKey = "";
        for (var i = 0; i < arrayObj1.length; i++) {
            currentKey = arrayObj1[i];
            if (object1[currentKey] !== null && object2[currentKey] !== null)
                if (!_.has(object2, currentKey) ||
                    !_.isEqual(object1[currentKey].toUpperCase(), object2[currentKey].toUpperCase()))
                    return false;
        }
        return result;
    };
user3180914
quelle
0

Hier haben Sie eine Möglichkeit, dies in einer Zeile für zwei Arrays zu tun:

const startArray = [1,2,3,4]
const newArray = [4,5,6]

const result = [...startArray, ...newArray.filter(a => !startArray.includes(a))]

console.log(result);
//Result: [1,2,3,4,5,6]
Jöcker
quelle
-1

Sie können jQuery grep verwenden und pushen, wenn keine Ergebnisse erzielt werden: http://api.jquery.com/jQuery.grep/

Es ist im Grunde die gleiche Lösung wie bei der "Erweiterung des Prototyps" -Lösung, jedoch ohne den Prototyp zu erweitern (oder zu verschmutzen).

jgroenen
quelle
-2

Sie können das Array mit foreach überprüfen und dann das Element einfügen, falls vorhanden. Andernfalls fügen Sie ein neues Element hinzu ...

Beispiel newItemValue & submitFields sind Schlüssel-Wert-Paare

> //submitFields existing array
>      angular.forEach(submitFields, function(item) {
>                   index++; //newItemValue new key,value to check
>                     if (newItemValue == item.value) {
>                       submitFields.splice(index-1,1);
>                         
>                     } });

                submitFields.push({"field":field,"value":value});
Taran
quelle