Array.push () jika tidak ada?

247

Bagaimana saya bisa mendorong ke array jika tidak ada nilai? Ini array saya:

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

Jika saya mencoba untuk mendorong lagi ke dalam array dengan salah satu name: "tom"atau text: "tasty", saya tidak ingin sesuatu terjadi ... tetapi jika tidak ada yang ada di sana maka saya ingin.push()

Bagaimana saya bisa melakukan ini?

tarnfeld
sumber
5
Gunakan kamus (hash / tree) sebagai ganti array.
Thomas Eding
Apakah semua ini tersedia dalam javascript?
Rahul
3
gunakan Set
Drax
1
Set tidak bekerja dengan berbagai objek
rffaguiar

Jawaban:

114

Anda dapat memperluas prototipe Array dengan metode khusus:

// 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
sumber
5
Saya pikir camparer Anda (pembanding?) Harus mengambil dua argumen, ini akan menyederhanakan kasus ketika nilai tambah inline dan bukan dalam variabel yang dapat Anda akses di fungsi Anda. array.pushIfNotExist ({name: "tom", text: "tasty"}, fungsi (a, b) {return a.name === b.name && a.text === b.text;});
Vincent Robert
26
Saya bertanya-tanya mengapa ini bukan bahasa asli - lupakan cara penerapannya - gagasan 'menambahkan hanya jika unik' begitu mendasar sehingga dianggap ada.
justSteve
9
Lebih baik memperluas prototipe Array dengan metode JavaScript 1.6 IndexOf daripada inArray Anda.
Eugene Gluhotorenko
7
Array.findIndex()adalah fungsi JS bawaan yang akan mencapai hal yang sama seperti kode Anda.
4
Memperluas objek bawaan secara langsung adalah praktik yang buruk.
Slava Fomin II
429

Untuk larik string (tetapi bukan larik objek), Anda dapat memeriksa apakah suatu item ada dengan memanggil .indexOf()dan jika tidak maka masukkan saja item ke dalam array:

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
sumber
50
Tidak yakin mengapa ini tidak ditandai sebagai benar. Itu tidak menggunakan eksternal, tidak perlu membuat ekstensi dan mati sederhana. Jawaban sempurna untuk pertanyaan ops.
pimbrouwers
39
Dalam pertanyaan awal, nilai-nilai array adalah objek, bukan string (dan solusi ini tidak berfungsi seperti jika nilai adalah objek).
Simon Hai
12
@ EmilPedersen - tidak juga. Coba if (a.indexOf({ name: "tom", text: "tasty" })!=-1) a.push({ name: "tom", text: "tasty" })dua kali. Ini akan menambahkan objek 'mirip' dua kali.
commonpike
18
Jawaban ini harus dihapus karena secara objektif salah, tetapi masih menarik jumlah upvote tertinggi.
nikola
2
Ini bukan jawaban yang benar, mengapa diterima? Ini hanya berfungsi untuk array Js, bukan objek dalam array.
digitai
100

Sangat mudah untuk dilakukan menggunakan Array.findIndexfungsi, yang mengambil fungsi sebagai argumen:

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
sumber
8
INI adalah jawabannya kawan !!
cepat
2
paling relevan untuk menambahkan elemen dalam array jika tidak ada
akshay bagade
1
Terima kasih, sedang mencari ini di mana-mana.
dt192
41

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

var cleanArray = $.unique(clutteredArray);

Anda mungkin tertarik pada makeArray juga

Contoh sebelumnya adalah yang terbaik dalam mengatakan bahwa periksa apakah ada sebelum mendorong. Saya melihat di belakang juga menyatakan Anda dapat mendeklarasikannya sebagai bagian dari prototipe (saya kira itu Kelas Ekstensi), jadi tidak ada peningkatan besar di bawah ini.

Kecuali saya tidak yakin apakah indexOf adalah rute yang lebih cepat daripada di Array? mungkin.

Array.prototype.pushUnique = function (item){
    if(this.indexOf(item) == -1) {
    //if(jQuery.inArray(item, this) == -1) {
        this.push(item);
        return true;
    }
    return false;
}
MistereeDevlord
sumber
22
Dari tautan jQuery: Note that this only works on arrays of DOM elements, not strings or numbers.Juga, indexOf tidak berfungsi di IE8 :(
dmathisen
Anda dapat menggunakan lodash _.indexOf, yang akan berfungsi di IE8
LTroya
25

Gunakan perpustakaan js seperti underscore.js karena alasan ini persis. Gunakan: gabungan: Menghitung gabungan dari array yang lewat: daftar item unik, secara berurutan, yang ada di satu atau lebih dari array.

_.union([1, 2, 3], [101, 2, 1, 10], [2, 1]);
=> [1, 2, 3, 101, 10]
Ronen Rabinovici
sumber
8
Catatan, ini mengembalikan array baru dan tidak benar-benar mendorong ke array yang ada.
ilovett
4
IMHO benar-benar tidak perlu membawa kerangka kerja untuk menguji sesuatu yang sangat sederhana
DrewT
24

Seperti ini?

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

Dengan objek

var item = {name: "tom", text: "tasty"}
var array = [{}]
if (!array.find(o => o.name === 'tom' && o.text === 'tasty'))
    array.push(item)
Ronnie Royston
sumber
4
array.findadalah ide yang buruk karena mencari seluruh array. Gunakan findIndex, yang hanya mencari sampai kemunculan pertama.
3
@ K48 sesuai dengan ini: stackoverflow.com/a/33759573/5227365 "find" berhenti setelah menemukan item
Pascal
19

Saya tahu ini adalah pertanyaan yang sangat lama, tetapi jika Anda menggunakan ES6 Anda dapat menggunakan versi yang sangat kecil:

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

Sangat mudah, pada awalnya tambahkan filter yang menghapus item - jika sudah ada, dan kemudian tambahkan melalui sebuah concat.

Ini adalah contoh yang lebih realistis:

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

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

Jika Anda array berisi objek, Anda bisa mengadaptasi fungsi filter seperti ini:

someArray.filter(f => f.some(s => s.id === myId)).concat([{ id: myId }])
Michael J. Zoidl
sumber
3
Solusi yang cukup elegan di sini. Terima kasih!
Jonathan Picazo
18

Dorong secara dinamis

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

Dalam metode sederhana

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

Jika array hanya berisi tipe primitif / array sederhana

var b = [1, 7, 8, 4, 3];
var newItem = 6;
b.indexOf(newItem) === -1 && b.push(newItem);
Gopala raja naika
sumber
2
Kesehatan ke tangan Anda. Solusi sederhana dan indah @ Goala raja naika
Nasimba
11

Saya sarankan Anda menggunakan Set ,

Set hanya memungkinkan entri unik, yang secara otomatis menyelesaikan masalah Anda.

Set dapat dinyatakan seperti ini:

const baz = new Set(["Foo","Bar"])
Michael McQuade
sumber
Terima kasih telah menunjukkan itu @Michael. Solusi yang bagus untuk saat kita ingin mempertahankan data yang berbeda dengan upaya minimal. FWIW, penting untuk dicatat bahwa kinerja array lebih baik karena membutuhkan lebih sedikit CPU untuk mengambil elemen ketika dibutuhkan.
Ben
Pertanyaannya adalah tentang Array.push, jadi Set.addsama dengan itu.
bryc
9

Kode mudah, jika 'indexOf' mengembalikan '-1' itu berarti elemen tidak ada di dalam array maka kondisi '=== -1' mengambil true / false.

Operator '&&' berarti 'dan', jadi jika kondisi pertama benar, kami dorong ke array.

array.indexOf(newItem) === -1 && array.push(newItem);
Eric Valero
sumber
@ D. Hukum Ya, jauh lebih baik sekarang.
Eric Valero
Ada jawaban lain yang diterima yang memberikan pertanyaan OP, dan mereka diposting beberapa waktu lalu. Saat mengirim jawaban, lihat: Bagaimana saya menulis jawaban yang baik? , harap pastikan Anda menambahkan solusi baru, atau penjelasan yang jauh lebih baik, terutama saat menjawab pertanyaan yang lebih lama.
help-info.de
4

Tidak yakin tentang kecepatan, tetapi stringification+ indexOfadalah pendekatan sederhana. Mulailah dengan mengubah array Anda menjadi string:

let strMyArray = JSON.stringify(myArray);

Kemudian untuk serangkaian pasangan atribut-nilai yang dapat Anda gunakan:

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

Menemukan seluruh objek lebih mudah:

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

Jika Anda membutuhkan sesuatu yang sederhana tanpa ingin memperpanjang prototipe 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);
}
docta_faustus
sumber
3

Jika ada yang memiliki persyaratan yang tidak terlalu rumit, inilah adaptasi saya atas jawaban untuk larik string sederhana:

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

Pembaruan: Ganti indexOf dan trim dengan alternatif jQuery untuk kompatibilitas IE8

Pengacara Setan
sumber
ini adalah solusi yang bagus, tetapi mengapa menggunakan trim?
Dejan Dozet
2

Saya menggunakan peta dan mengurangi untuk melakukan ini dalam kasus di mana Anda ingin mencari dengan properti tertentu dari suatu objek, berguna karena melakukan persamaan objek langsung akan sering gagal.

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
sumber
2

Contoh singkat:

if (typeof(arr[key]) === "undefined") {
  arr.push(key);
}
GigolNet Guigolachvili
sumber
1
Tidak benar. Kami tidak tertarik untuk mendorong kunci, kami ingin mendorong pasangan nama-nilai, tetapi hanya jika itu belum ada.
Stefan
2

a adalah array dari objek yang Anda miliki

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

Anda dapat menggunakan metode findIndex dengan fungsi panggilan balik dan parameter "ini" -nya.

Catatan: browser lama tidak tahu findIndex tetapi polyfill tersedia.

Kode sampel (perhatikan bahwa dalam pertanyaan asli, objek baru didorong hanya jika tidak ada datanya dalam objek yang didorong sebelumnya):

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 Hai
sumber
1

Saya kira saya sudah terlambat untuk menjawab di sini, tetapi inilah yang akhirnya saya dapatkan untuk manajer email yang saya tulis. Pekerjaan itu yang saya butuhkan.

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
sumber
0

Ini berfungsi untuk perbandingan objek. Dalam beberapa kasus, Anda mungkin memiliki banyak bidang untuk dibandingkan. Cukup loop array dan panggil fungsi ini dengan item yang ada dan item baru.

 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;
    };
pengguna3180914
sumber
0

Di sini Anda memiliki cara untuk melakukannya dalam satu baris untuk dua array:

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
sumber
-1

Anda dapat menggunakan jQuery grep dan mendorong jika tidak ada hasil: http://api.jquery.com/jQuery.grep/

Ini pada dasarnya solusi yang sama seperti dalam solusi "memperluas prototipe", tetapi tanpa memperluas (atau mencemari) prototipe.

jgroenen
sumber
-2

Anda dapat memeriksa array menggunakan foreach dan kemudian pop item jika ada, jika tidak tambahkan item baru ...

sampel NewItemValue & submitFields adalah pasangan kunci, nilai

> //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
sumber