Array.push () se não existir?


247

Como posso inserir uma matriz se nenhum valor existe? Aqui está minha matriz:

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

Se eu tentasse entrar novamente no array com um name: "tom"ou outro text: "tasty", não quero que nada aconteça ... mas se nenhum deles estiver lá, quero que.push()

Como posso fazer isso?


5
Use um dicionário (hash / árvore) em vez de uma matriz.
— Thomas Eding

Todos estes estão disponíveis em javascript?
— R1 #


3
use um Set
— Drax

1
Set não funciona com matriz de objetos
— rffaguiar

Respostas:


114

Você pode estender o protótipo Array com um 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; 
});

5
Eu acho que o seu camparer (comparador?) Deve ter dois argumentos, isso simplificaria o caso quando o valor agregado estiver embutido e não em uma variável que você possa acessar em sua função. array.pushIfNotExist ({name: "tom", texto: "tasty"}), função (a, b) {retorna a.name === b.name && a.text === b.text;});
— Vincent Robert

26
Estou me perguntando por que isso não é nativo da linguagem - esqueça como é implementado - a idéia de 'adicionar apenas se único' é tão fundamental que se supõe que exista.
— justSteve

9
É melhor estender o protótipo da matriz com o método JavaScript 1.6 IndexOf em vez do seu inArray.
— Eugene Gluhotorenko

7
Array.findIndex()é uma função JS interna que obterá o mesmo que seu código.

4
Estender objetos internos diretamente é uma prática ruim.
— Slava Fomin II

429

Para uma matriz de seqüências de caracteres (mas não uma matriz de objetos), você pode verificar se um item existe chamando .indexOf()e se não existir , basta enviar o item para a 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)


50
Não sei por que isso não está marcado como correto. Ele não usa elementos externos, não requer a criação de uma extensão e é simples. Resposta perfeita para a questão das operações.
— Pimbrouwers

39
Na pergunta inicial, os valores da matriz são objetos, não seqüências de caracteres (e essa solução não funciona como se os valores fossem objetos).
— Simon Hi

12
@EmilPedersen - na verdade não. Tente if (a.indexOf({ name: "tom", text: "tasty" })!=-1) a.push({ name: "tom", text: "tasty" })duas vezes. Ele adicionará um objeto 'semelhante' duas vezes.
— commonpike

18
Esta resposta deve ser removida, pois está objetivamente errada, mas ainda atraiu o maior número de votos.
— Nikola

2
Esta não é uma resposta correta, por que é aceita? Funciona apenas para matrizes Js, não para objetos dentro de matrizes.
— digitai

100

É bastante fácil usar a Array.findIndexfunção, que aceita uma função 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")

8
Esta é a resposta pessoal !!
— Jafed4

2
mais relevantes para adicionar um elemento na matriz se não estiver presente
— akshay bagade

1
Obrigado, estava procurando isso em todos os lugares.
— dt192 30/05/19

41

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

var cleanArray = $.unique(clutteredArray);

você também pode estar interessado em makeArray

O exemplo anterior é melhor dizer que verifique se existe antes de pressionar. Em retrospectiva, também afirma que você pode declará-lo como parte do protótipo (acho que é conhecido como Extensão de Classe), portanto, não há grande aprimoramento abaixo.

Exceto que não tenho certeza se indexOf é uma rota mais rápida que o inArray? provavelmente.

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

22
No link jQuery: Note that this only works on arrays of DOM elements, not strings or numbers.Além disso, o indexOf não funciona no IE8 :(
— dmathisen

Você pode usar o lodash _.indexOf, que funcionará no IE8
— LTroya 4/16

25

Use uma biblioteca js como underscore.js por esses motivos exatamente. Uso: união: Calcula a união das matrizes passadas: a lista de itens exclusivos, em ordem, que estão presentes em uma ou mais matrizes.

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

8
Observe que isso retorna uma nova matriz e, na verdade, não envia para uma matriz existente.
— precisa saber é

4
IMHO realmente não há necessidade de criar uma estrutura para testar algo tão simples #
— DrewT 30/12/15

24

Como isso?

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

Com objeto

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

4
array.findé uma péssima ideia, porque pesquisa toda a matriz. Use findIndex, que pesquisa apenas até a primeira ocorrência.

3
@ K48 de acordo com o seguinte: stackoverflow.com/a/33759573/5227365 "find" para depois de encontrar o item
— Pascal

19

Sei que essa é uma pergunta muito antiga, mas se você estiver usando o ES6, poderá usar uma versão muito pequena:

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

Muito fácil, primeiro adicione um filtro que remova o item - se ele já existir, e adicione-o através de uma concat.

Aqui está um exemplo mais realista:

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

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

Se seu array contiver objetos, você poderá adaptar a função de filtro da seguinte forma:

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

3
Uma solução bastante elegante aqui. Obrigado!
— Jonathan Picazo

18

Empurre dinamicamente

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

No método simples

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

Se a matriz contiver apenas tipos primitivos / matriz simples

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

2
Saúde para o seu hands.Simple e bela solução @Gopala raja Naika
— Nasimba

11

Eu sugiro que você use um conjunto ,

Os conjuntos permitem apenas entradas exclusivas, que resolvem automaticamente o seu problema.

Os conjuntos podem ser declarados da seguinte forma:

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

Obrigado por apontar isso para @ Michael. Boa solução para quando queremos manter dados distintos com o mínimo de esforço. FWIW, é importante observar que o desempenho da matriz é melhor, pois requer menos CPU para buscar o elemento quando necessário.
— Ben

A pergunta é sobre Array.push, então Set.addé o equivalente a isso.
— bryc 25/05

9

Código fácil, se 'indexOf' retornar '-1' significa que o elemento não está dentro da matriz, e a condição '=== -1' recuperará verdadeiro / falso.

O operador '&&' significa 'e', ​​portanto, se a primeira condição for verdadeira, enviamos para a matriz.

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

@ D.Lawrence Sim, muito melhor agora.
— Eric Valero

Existem outras respostas aceitas que fornecem a pergunta do OP e foram publicadas há algum tempo. Ao postar uma resposta, consulte: Como redigir uma boa resposta? , adicione uma nova solução ou uma explicação substancialmente melhor, especialmente ao responder a perguntas mais antigas.
— help-info.de

4

Não tenho certeza sobre velocidade, mas stringification+ indexOfé uma abordagem simples. Comece transformando sua matriz em uma string:

let strMyArray = JSON.stringify(myArray);

Em seguida, para uma série de pares atributo-valor, você pode usar:

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

Encontrar um objeto inteiro é mais simples:

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

3

Caso você precise de algo simples sem querer estender o protótipo 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

Caso alguém tenha requisitos menos complicados, eis a minha adaptação da resposta para uma matriz simples de strings:

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

Atualização: indexOf e aparagem substituídos por alternativas jQuery para compatibilidade com o IE8


é uma boa solução, mas por que usar aparar?
— Dejan Dozet

2

Usei map e reduzi para fazer isso no caso em que você deseja pesquisar por uma propriedade específica de um objeto, útil como fazer a igualdade direta de objetos geralmente falhará.

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

Breve exemplo:

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

1
Incorreto. Não estamos interessados ​​em pressionar a tecla, queremos pressionar um par nome-valor, mas apenas se ele ainda não existir.
— 31518 Stefan

2

a é a matriz de objetos que você possui

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

1

Você pode usar o método findIndex com uma função de retorno de chamada e seu parâmetro "this".

Nota: navegadores antigos não conhecem o findIndex, mas um polyfill está disponível.

Código de amostra (lembre-se de que, na pergunta original, um novo objeto seja enviado apenas se nenhum dos seus dados estiver em objetos enviados anteriormente):

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

Eu acho que estou atrasado para responder aqui, no entanto, é isso que eu finalmente criei para um gerente de correio que escrevi. Funciona é tudo o que eu preciso.

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

Isso está funcionando func para uma comparação de objetos. Em alguns casos, você pode ter muitos campos para comparar. Basta fazer um loop na matriz e chamar essa função com itens existentes e novo item.

 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

Aqui você tem uma maneira de fazer isso em uma linha para duas matrizes:

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]


-2

Você pode verificar a matriz usando foreach e, em seguida, exibir o item, se existir, caso contrário, adicione um novo item ...

exemplo newItemValue e submitFields são pares chave, valor

> //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});
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.