Array.push () si n'existe pas?


247

Comment puis-je pousser dans un tableau si aucune valeur n'existe? Voici mon tableau:

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

Si j'ai essayé de pousser à nouveau dans le tableau avec l'un name: "tom"ou l' autre text: "tasty", je ne veux pas qu'il se passe quoi que ce soit ... mais si aucun d'eux n'est là, alors je veux que cela se produise.push()

Comment puis-je faire ceci?


5
Utilisez un dictionnaire (hachage / arbre) au lieu d'un tableau.
Thomas Eding, du

Tous ces éléments sont-ils disponibles en javascript?
rahul


3
utiliser un Set
Drax

1
L'ensemble ne fonctionne pas avec un tableau d'objets
rffaguiar

Réponses:


114

Vous pouvez étendre le prototype Array avec une méthode personnalisée:

// 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; 
});

5
Je pense que votre campeur (comparateur?) Devrait prendre deux arguments, cela simplifierait le cas lorsque la valeur ajoutée est en ligne et non dans une variable à laquelle vous pouvez accéder dans votre fonction. array.pushIfNotExist ({name: "tom", text: "tasty"}, function (a, b) {return a.name === b.name && a.text === b.text;});
Vincent Robert

26
Je me demande pourquoi ce n'est pas natif de la langue - oubliez comment il est mis en œuvre - l'idée de «n'ajouter que si unique» est si fondamentale qu'on suppose qu'elle existe.
justSteve

9
Il est préférable d'étendre le prototype Array avec la méthode JavaScript 1.6 IndexOf au lieu de votre inArray.
Eugene Gluhotorenko

7
Array.findIndex()est une fonction JS intégrée qui réalisera la même chose que votre code.

4
L'extension directe d'objets intégrés est une mauvaise pratique.
Slava Fomin II

429

Pour un tableau de chaînes (mais pas un tableau d'objets), vous pouvez vérifier si un élément existe en appelant .indexOf()et s'il ne le fait pas simplement pousser l'élément dans le tableau:

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)


50
Je ne sais pas pourquoi cela n'est pas signalé comme correct. Il n'utilise aucun externe, ne nécessite pas de créer une extension et est d'une simplicité déconcertante. Réponse parfaite à la question des opérations.
pimbrouwers

39
Dans la question initiale, les valeurs du tableau sont des objets, pas des chaînes (et cette solution ne fonctionne pas comme si les valeurs étaient des objets).
Simon Hi

12
@EmilPedersen - pas vraiment. Essayez if (a.indexOf({ name: "tom", text: "tasty" })!=-1) a.push({ name: "tom", text: "tasty" })deux fois. Il ajoutera un objet «similaire» deux fois.
commonpike

18
Cette réponse devrait être supprimée car elle est objectivement erronée, mais elle a quand même attiré le plus grand nombre de votes positifs.
nikola

2
Ce n'est pas une bonne réponse, pourquoi est-elle acceptée? Cela ne fonctionne que pour les tableaux Js, pas pour les objets dans les tableaux.
digitai

100

C'est assez facile à faire en utilisant la Array.findIndexfonction, qui prend une fonction comme argument:

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

8
CECI est la réponse les gars !!
jafed

2
le plus pertinent pour ajouter un élément dans le tableau s'il n'est pas présent
akshay bagade

1
Merci, je cherchais ça partout.
dt192

41

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

var cleanArray = $.unique(clutteredArray);

vous pourriez également être intéressé par makeArray

L'exemple précédent est préférable de dire que vérifier s'il existe avant de pousser. Avec le recul, il indique également que vous pouvez le déclarer comme faisant partie du prototype (je suppose que c'est alias Extension de classe), donc pas de grande amélioration ci-dessous.

Sauf que je ne sais pas si indexOf est un itinéraire plus rapide que inArray? Probablement.

Array.prototype.pushUnique = function (item){
    if(this.indexOf(item) == -1) {
    //if(jQuery.inArray(item, this) == -1) {
        this.push(item);
        return true;
    }
    return false;
}

22
À partir du lien jQuery: Note that this only works on arrays of DOM elements, not strings or numbers.En outre, indexOf ne fonctionne pas dans IE8 :(
dmathisen

Vous pouvez utiliser lodash _.indexOf, qui fonctionnera dans IE8
LTroya

25

Utilisez une bibliothèque js comme underscore.js pour ces raisons exactement. Utilisation: union: calcule l'union des tableaux passés: la liste des éléments uniques, dans l'ordre, qui sont présents dans un ou plusieurs des tableaux.

_.union([1, 2, 3], [101, 2, 1, 10], [2, 1]);
=> [1, 2, 3, 101, 10]

8
Remarque, cela renvoie un nouveau tableau et ne pousse pas réellement vers un tableau existant.
ilovett


24

Comme ça?

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

Avec objet

var item = {name: "tom", text: "tasty"}
var array = [{}]
if (!array.find(o => o.name === 'tom' && o.text === 'tasty'))
    array.push(item)

4
array.findest une mauvaise idée car il recherche l'ensemble du tableau. Utilisez findIndex, qui recherche uniquement jusqu'à la première occurrence.

3
@ K48 selon ceci: stackoverflow.com/a/33759573/5227365 "find" s'arrête après avoir trouvé l'article
Pascal

19

Je sais que c'est une très vieille question, mais si vous utilisez ES6, vous pouvez utiliser une toute petite version:

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

Très facile, ajoutez d'abord un filtre qui supprime l'élément - s'il existe déjà, puis ajoutez-le via un concat.

Voici un exemple plus réaliste:

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

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

Si votre tableau contient des objets, vous pouvez adapter la fonction de filtre comme ceci:

someArray.filter(f => f.some(s => s.id === myId)).concat([{ id: myId }])

3
Une solution assez élégante ici. Merci!
Jonathan Picazo

18

Poussez dynamiquement

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

En méthode simple

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

Si le tableau contient uniquement des types primitifs / tableau simple

var b = [1, 7, 8, 4, 3];
var newItem = 6;
b.indexOf(newItem) === -1 && b.push(newItem);

2
Santé à vos mains. Solution simple et belle @ Gopala raja naika
Nasimba

11

Je vous suggère d'utiliser un ensemble ,

Les ensembles n'autorisent que des entrées uniques, ce qui résout automatiquement votre problème.

Les ensembles peuvent être déclarés comme suit:

const baz = new Set(["Foo","Bar"])

Merci d'avoir signalé @Michael. Bonne solution lorsque nous voulons conserver des données distinctes avec un minimum d'effort. FWIW, il est important de noter que les performances du tableau sont meilleures car elles nécessitent moins de CPU pour récupérer l'élément lorsque cela est nécessaire.
Ben

La question porte sur Array.push, Set.addest donc l'équivalent de cela.
bryc

9

Code facile, si 'indexOf' renvoie '-1' cela signifie que l'élément n'est pas à l'intérieur du tableau alors la condition '=== -1' récupère vrai / faux.

L'opérateur '&&' signifie 'et', donc si la première condition est vraie, nous la poussons vers le tableau.

array.indexOf(newItem) === -1 && array.push(newItem);

@ D.Lawrence Oui, tellement mieux maintenant.
Eric Valero

Il existe d'autres réponses acceptées qui fournissent la question du PO, et elles ont été publiées il y a quelque temps. Lors de la publication d'une réponse, voir: Comment puis-je écrire une bonne réponse? , assurez-vous d'ajouter une nouvelle solution ou une meilleure explication, en particulier lorsque vous répondez à des questions plus anciennes.
help-info.de

4

Pas sûr de la vitesse, mais stringification+ indexOfest une approche simple. Commencez par transformer votre tableau en chaîne:

let strMyArray = JSON.stringify(myArray);

Ensuite, pour une série de paires attribut-valeur, vous pouvez utiliser:

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

Trouver un objet entier est plus simple:

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

3

Au cas où vous auriez besoin de quelque chose de simple sans vouloir étendre le prototype Array:

// 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);
}

3

Dans le cas où quelqu'un a des exigences moins compliquées, voici mon adaptation de la réponse pour un simple tableau de chaînes:

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

Mise à jour: IndexOf et trim remplacés par des alternatives jQuery pour la compatibilité IE8


c'est une bonne solution, mais pourquoi utiliser la garniture?
Dejan Dozet

2

J'ai utilisé mapper et réduire pour le faire dans le cas où vous souhaitez rechercher par la propriété spécifique d'un objet, utile car faire l'égalité directe d'objet échouera souvent.

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");
}

2

Petit exemple:

if (typeof(arr[key]) === "undefined") {
  arr.push(key);
}

1
Pas correcte. Nous ne souhaitons pas pousser la clé, nous voulons pousser une paire nom-valeur, mais seulement si elle n'existe pas déjà.
Stefan

2

a est le tableau d'objets que vous avez

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

1

Vous pouvez utiliser la méthode findIndex avec une fonction de rappel et son paramètre "this".

Remarque: les anciens navigateurs ne connaissent pas findIndex mais un polyfill est disponible.

Exemple de code (veillez à ce que dans la question d'origine, un nouvel objet ne soit poussé que si aucune de ses données ne se trouve dans des objets poussés précédemment):

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

1

Je suppose que je suis trop tard pour répondre ici, mais c'est ce que j'ai finalement trouvé pour un gestionnaire de messagerie que j'ai écrit. Des œuvres, c'est tout ce dont j'ai besoin.

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>


0

Cela fonctionne pour une comparaison d'objets. Dans certains cas, vous pourriez avoir beaucoup de champs à comparer. Bouclez simplement le tableau et appelez cette fonction avec un élément existant et un nouvel élément.

 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;
    };

0

Ici, vous avez un moyen de le faire en une seule ligne pour deux tableaux:

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]

-1

Vous pouvez utiliser jQuery grep et pousser si aucun résultat: http://api.jquery.com/jQuery.grep/

C'est fondamentalement la même solution que dans la solution "étendre le prototype", mais sans étendre (ni polluer) le prototype.


-2

Vous pouvez vérifier le tableau à l'aide de foreach, puis faire apparaître l'élément s'il existe, sinon ajouter un nouvel élément ...

les exemples newItemValue et submitFields sont des paires clé / valeur

> //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});
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.