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?


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

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)


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

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

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]

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)

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 }])

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

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

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

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

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

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


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

2

Contoh singkat:

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

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

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

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>


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

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]

-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.


-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});
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.