Matriz.push() si no existe?


¿Cómo puedo insertar un array si no existen valores? Aquí está mi matriz:

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

Si intento empujar de nuevo en la matriz con name: "tom" o text: "tasty", no quiero que pase nada... pero si ninguno de ellos está allí entonces quiero que .push()

¿Cómo puedo hacer esto?

Author: ManoDestra, 2010-01-01

16 answers

Podría extender el prototipo de matriz con un método personalizado:

// 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; 
});
 86
Author: Darin Dimitrov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-08-16 20:52:55

Para una matriz de cadenas (pero no una matriz de objetos), puede verificar si existe un elemento llamando a .indexOf() y si no lo hace, simplemente empuje el elemento en la matriz:

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)
 261
Author: Jiří Zahálka,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-01-10 05:41:38

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

var cleanArray = $.unique(clutteredArray);

Usted podría estar interesado en makeArray también

El ejemplo anterior es mejor para decir que compruebe si existe antes de empujar. Veo en retrospectiva que también indica que se puede declarar como parte del prototipo (supongo que es aka Extensión de clase), por lo que no hay gran mejora a continuación.

Excepto que no estoy seguro si indexOf es una ruta más rápida que inArray? Probablemente.

Array.prototype.pushUnique = function (item){
    if(this.indexOf(item) == -1) {
    //if(jQuery.inArray(item, this) == -1) {
        this.push(item);
        return true;
    }
    return false;
}
 40
Author: MistereeDevlord,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-10-13 23:21:01

Es bastante fácil de hacer usando la función Array.findIndex, que toma una función como argumento:

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")
 30
Author: ashish yadav,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-01-15 09:51:20

Use una biblioteca js como underscore.js por estas razones exactamente. Use: union: Calcula la unión de los arrays pasados: la lista de elementos únicos, en orden, que están presentes en uno o más de los arrays.

_.union([1, 2, 3], [101, 2, 1, 10], [2, 1]);
=> [1, 2, 3, 101, 10]
 23
Author: Ronen Rabinovici,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-06-02 18:39:02

¿Así?

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

Con objeto

var item = {name: "tom", text: "tasty"}
var array = [{}]
if (!array.find(o => o.name === 'tom' && o.text === 'tasty'))
    array.push(item)
 17
Author: Ron Royston,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-07-25 13:18:32

En caso de que necesite algo simple sin querer extender el prototipo de matriz:

// 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
Author: docta_faustus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-01-15 06:37:27

Sé que esta es una pregunta muy antigua, pero si estás usando ES6 puedes usar una versión muy pequeña:

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

Muy fácil, al principio añadir un filtro que elimina el elemento - si ya existe, y luego añadirlo a través de un concat.

Aquí hay un ejemplo más realista:

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

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

Si su matriz contiene objetos, podría adaptar la función de filtro de esta manera:

someArray.filter(f => f.some(s => s.id === myId)).concat([{ id: myId }])
 3
Author: Michael J. Zoidl,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-04-24 14:28:49

No estoy seguro de la velocidad, pero stringification + indexOf es un enfoque simple. Comience con convertir su matriz en una cadena:

let strMyArray = JSON.stringify(myArray);

Entonces para una serie de pares atributo-valor puedes usar:

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

Encontrar un objeto completo es más sencillo:

if (strMyArray.indexOf(JSON.stringify(objAddMe) === -1) { 
   myArray.push(objAddMe);
}
 3
Author: moshefnord,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-07-19 16:25:54

Utilicé map y reduce para hacer esto en el caso de que desee buscar por la propiedad a específica de un objeto, útil ya que hacer igualdad directa de objetos a menudo fallará.

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
Author: Adrian Smith,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-08-23 17:51:35

En caso de que alguien tenga requisitos menos complicados, aquí está mi adaptación de la respuesta para una matriz de cadenas simple:

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

Actualización: Reemplazado indexOf y trim con alternativas jQuery para IE8 compatability

 2
Author: Scott Beeson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-09-25 04:05:53

Puede usar el método findIndex con una función callback y su parámetro "this".

Nota: los navegadores antiguos no conocen findIndex, pero hay un polyfill disponible.

Código de ejemplo (tenga cuidado de que en la pregunta original, un nuevo objeto se empuje solo si ninguno de sus datos está en objetos empujados previamente):

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
Author: Simon Hi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-11-07 14:40:29

Esto funciona func para una comparación de objetos. En algunos casos, es posible que tenga muchos campos para comparar. Simplemente haga un bucle en la matriz y llame a esta función con un elemento existente y un nuevo elemento.

 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
Author: user3180914,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-18 05:11:34

Breve ejemplo:

if (typeof(arr[key]) === "undefined") {
  arr.push(key);
}
 0
Author: GigolNet Guigolachvili,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-07-26 16:59:26

Puede usar jQuery grep y push si no hay resultados: http://api.jquery.com/jQuery.grep /

Es básicamente la misma solución que en la solución "extender el prototipo", pero sin extender (o contaminar) el prototipo.

 -1
Author: jgroenen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-07-24 12:59:56

Puede comprobar la matriz utilizando foreach y luego pop el elemento si existe de lo contrario añadir nuevo elemento...

Ejemplo newItemValue & submitFields son clave, pares de valores

> //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});
 -1
Author: Taran,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-07-13 17:01:09