Bagaimana cara saya memeriksa apakah array menyertakan nilai dalam JavaScript?

3997

Apa cara paling ringkas dan efisien untuk mengetahui apakah array JavaScript berisi nilai?

Ini adalah satu-satunya cara saya tahu untuk melakukannya:

function contains(a, obj) {
    for (var i = 0; i < a.length; i++) {
        if (a[i] === obj) {
            return true;
        }
    }
    return false;
}

Apakah ada cara yang lebih baik dan lebih ringkas untuk mencapai ini?

Ini sangat terkait dengan pertanyaan Stack Overflow Cara terbaik untuk menemukan item dalam JavaScript Array? yang membahas menemukan objek dalam array menggunakan indexOf.

brad
sumber
49
baru saja diuji: cara Anda sebenarnya yang tercepat untuk seluruh browser: jsperf.com/find-element-in-obj-vs-array/2 (terlepas dari pra-penghematan a. panjang dalam variabel) saat menggunakan indexOf (seperti pada $ .inArray) jauh lebih lambat
Jörn Berkefeld
17
banyak yang menjawab bahwa Array # indexOf adalah pilihan terbaik Anda di sini. Tetapi jika Anda menginginkan sesuatu yang dapat dilemparkan dengan benar ke Boolean, gunakan ini: ~[1,2,3].indexOf(4)akan mengembalikan 0 yang akan bernilai false, sedangkan ~[1,2,3].indexOf(3)akan mengembalikan -3 yang akan dievaluasi sebagai benar.
Lordord
8
~bukan apa yang ingin Anda gunakan untuk mengkonversi ke boolean, untuk itu Anda butuhkan !. Tetapi dalam hal ini Anda ingin memeriksa kesetaraan dengan -1, sehingga fungsi mungkin berakhir return [1,2,3].indexOf(3) === -1; ~adalah bukan biner, itu akan membalikkan setiap bit dari nilai secara individual.
mcfedr
14
@ Iordvlad [1,2,3].indexOf(4)sebenarnya akan mengembalikan -1 . Seperti @mcfedr tunjukkan, ~adalah operator bitwise-NOT , lihat ES5 11.4.8. Masalahnya, karena representasi biner -1hanya terdiri dari 1, komplemennya adalah 0, yang dievaluasi sebagai false. Komplemen dari nomor lain akan menjadi nol, karenanya benar. Jadi, ~berfungsi dengan baik dan sering digunakan bersamaan indexOf.
mknecht
5
Judul itu menyesatkan. Dimana [[1,2],[3,4]].includes([3,4])?
mplungjan

Jawaban:

4379

Peramban modern memiliki Array#includes, yang melakukan hal itu dan didukung secara luas oleh semua orang kecuali IE:

console.log(['joe', 'jane', 'mary'].includes('jane')); //true

Anda juga dapat menggunakan Array#indexOf, yang kurang langsung, tetapi tidak memerlukan polyfill untuk browser yang sudah ketinggalan zaman.


Banyak kerangka kerja juga menawarkan metode serupa:

Perhatikan bahwa beberapa kerangka kerja menerapkan ini sebagai fungsi, sementara yang lain menambahkan fungsi ke prototipe array.

kode kode
sumber
42
Mootools juga memiliki Array. Isi yang mengembalikan boolean, yang terdengar seperti pertanyaan nyata di sini.
Ryan Florence
22
prototipe juga memiliki Array.includeyang mengembalikan boolean
user102008
46
Jika Anda menggunakan peramban yang bagus, Anda bisa menggunakanarray.indexOf(object) != -1
Sam Soffes
13
Juga, jangan gunakan indexOf sendiri sebagai syarat, karena elemen pertama akan mengembalikan 0 dan akan dievaluasi sebagai falsy
plus-
241
inArrayadalah nama yang mengerikan untuk fungsi yang mengembalikan indeks elemen, dan -1jika itu tidak ada. Saya harapkan boolean dikembalikan.
Tim
434

Pembaruan dari 2019: Jawaban ini dari 2008 (11 tahun!) Dan tidak relevan untuk penggunaan JS modern. Peningkatan kinerja yang dijanjikan didasarkan pada tolok ukur yang dilakukan di browser saat itu. Mungkin tidak relevan dengan konteks eksekusi JS modern. Jika Anda membutuhkan solusi yang mudah, cari jawaban lain. Jika Anda membutuhkan kinerja terbaik, patok untuk diri sendiri di lingkungan eksekusi yang relevan.

Seperti yang orang lain katakan, iterasi melalui array mungkin adalah cara terbaik, tetapi telah terbukti bahwa whileloop yang menurun adalah cara tercepat untuk beralih di JavaScript. Jadi, Anda mungkin ingin menulis ulang kode Anda sebagai berikut:

function contains(a, obj) {
    var i = a.length;
    while (i--) {
       if (a[i] === obj) {
           return true;
       }
    }
    return false;
}

Tentu saja, Anda juga dapat memperpanjang prototipe Array:

Array.prototype.contains = function(obj) {
    var i = this.length;
    while (i--) {
        if (this[i] === obj) {
            return true;
        }
    }
    return false;
}

Dan sekarang Anda cukup menggunakan yang berikut ini:

alert([1, 2, 3].contains(2)); // => true
alert([1, 2, 3].contains('2')); // => false
Damir Zekić
sumber
22
"Terbukti" adalah kata yang kuat. Mesin JS terus membaik, dan waktu pelaksanaan yang diukur 3 tahun yang lalu sudah sangat usang.
orip
2
@ Damir - Saya setuju. Mungkin mengubah sampel untuk menggunakan indexOf jika tersedia, supaya orang menyalin-menempel kode ini secara membabi buta akan mendapatkan kinerja terbaik yang mereka bisa.
orip
1
@ cbmeeks ya, perawatan sangat dibutuhkan. Itu mungkin kasus melakukan for (o in array)yang seharusnya tidak dilakukan ketika perulangan melalui array umumnya ...
Damir Zekić
1
Cara terbaik untuk melakukan ini adalah memeriksa apakah [1, 2, 3] .indexOf (1)> -1
Devin G Rhode
207

indexOf mungkin, tetapi ini adalah "ekstensi JavaScript ke standar ECMA-262; karena itu mungkin tidak ada dalam implementasi standar lainnya."

Contoh:

[1, 2, 3].indexOf(1) => 0
["foo", "bar", "baz"].indexOf("bar") => 1
[1, 2, 3].indexOf(4) => -1

AFAICS Microsoft tidak menawarkan semacam alternatif untuk ini, tetapi Anda dapat menambahkan fungsionalitas serupa ke array di Internet Explorer (dan browser lain yang tidak mendukung indexOf) jika Anda ingin, sebagai diungkapkan oleh pencarian Google cepat (misalnya, yang ini ).

cic
sumber
sebenarnya, ada contoh implementasi ekstensi indexOf untuk browser yang tidak mendukungnya di halaman developer.mozilla.org yang Anda tautkan.
Lloyd Cotten
sebenarnya, jika Anda menambahkan indexof ke prototipe Array untuk browser yang tidak mendukungnya (yaitu IE7) mereka juga akan mencoba untuk mengulang fungsi ini ketika perulangan melalui item dalam array. menjijikan.
CpILL
apakah ini berlaku untuk memeriksa Objek.? Saya tidak berpikir itu berfungsi dalam kasus Obyek
Himesh Aadeshara
169

ECMAScript 7 memperkenalkan Array.prototype.includes .

Dapat digunakan seperti ini:

[1, 2, 3].includes(2); // true
[1, 2, 3].includes(4); // false

Ia juga menerima argumen opsional kedua fromIndex:

[1, 2, 3].includes(3, 3); // false
[1, 2, 3].includes(3, -1); // true

Tidak seperti indexOf, yang menggunakan Strict Equality Comparison , includesmembandingkan menggunakan algoritma kesetaraan SameValueZero . Itu berarti bahwa Anda dapat mendeteksi jika array menyertakan NaN:

[1, 2, NaN].includes(NaN); // true

Juga tidak seperti indexOf, includestidak melewatkan indeks yang hilang:

new Array(5).includes(undefined); // true

Saat ini masih berupa konsep tetapi dapat di- polyfill agar berfungsi di semua browser.

Oriol
sumber
3
Tidak didukung untuk IE dan Microsfot Edge (2015) ( developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… )
Adriano Resende
1
Juga relevan, tabel kompatibilitas ES7 (sepertinya chrome mendukungnya sekarang)
styfle
apakah ini berlaku untuk memeriksa Objek.? Saya tidak berpikir itu berfungsi dalam kasus Obyek
Himesh Aadeshara
128

Jawaban teratas mengasumsikan tipe primitif tetapi jika Anda ingin mengetahui apakah array berisi objek dengan beberapa sifat, Array.prototype.some () adalah solusi yang sangat elegan:

const items = [ {a: '1'}, {a: '2'}, {a: '3'} ]

items.some(item => item.a === '3')  // returns true
items.some(item => item.a === '4')  // returns false

Yang menyenangkan tentang itu adalah bahwa iterasi dibatalkan setelah elemen ditemukan sehingga siklus iterasi yang tidak perlu terhindar.

Juga, itu sangat cocok dalam sebuah ifpernyataan karena mengembalikan boolean:

if (items.some(item => item.a === '3')) {
  // do something
}

* Seperti yang ditunjukkan oleh jamess dalam komentar, pada saat jawaban ini, September 2018, Array.prototype.some()didukung penuh: tabel dukungan caniuse.com

Michael
sumber
1
Sampai hari ini, September 2018, Array.prototype.some () didukung penuh: meja dukungan
caniuse.com
1
Bekerja di Node> = 8,10 untuk AWS Node.js Lambda, jadi ini bagus. Solusi yang sangat bersih dan sederhana! 👍🏻
Jordan
1
@ jamess Mungkin didukung dengan baik, tetapi ingat bahwa Arrow functionsdalam contoh ini tidak didukung dengan baik. Untuk detail lebih lanjut lihat di sini: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Kamil Witkowski
Apakah ada hubungan arus pendek? Atau apakah itu mengulangi seluruh array bahkan jika itu menemukan nilai?
Douglas Gaskell
@DouglasGaskell batalkan iterasi yang pernah ditemukan (disebutkan dalam jawaban)
Michael
112

Katakanlah Anda telah mendefinisikan array seperti:

const array = [1, 2, 3, 4]

Di bawah ini adalah tiga cara untuk memeriksa apakah ada 3di sana. Semuanya kembali trueataufalse .

Metode Array Asli (sejak ES2016) ( tabel kompatibilitas )

array.includes(3) // true

Sebagai metode Array khusus (sebelum ES2016)

// Prefixing the method with '_' to avoid name clashes
Object.defineProperty(Array.prototype, '_includes', { value: function (v) { return this.indexOf(v) !== -1 }})
array._includes(3) // true

Fungsi sederhana

const includes = (a, v) => a.indexOf(v) !== -1
includes(array, 3) // true
william malo
sumber
Mengembalikan nilai true jika "b" ada dalam array "a" ... Saya tidak tahu bagaimana lagi menjelaskannya ...
william malo
4
Bagian ini saya tidak mengerti "!! ~". Dan saya pikir ini tidak akan berfungsi di IE8 karena IE8 tidak mendukung indexOf () pada objek Array.
svlada
62
"~" adalah operator yang mengatur, membalik dan mengurangi 1 dari suatu angka. indexOf mengembalikan -1 jika gagal, jadi "~" mengubah -1 menjadi "0". menggunakan "!!" mengubah angka menjadi boleans (!! 0 === false)
william malo
1
Keren, tapi serius demi kesederhanaan, bukan hanya a.indexOf (b)> - 1, karena "> -1" .length === "!! ~" .length
super
2
Saya akan menyebut kurangnya pengetahuan tentang efek dari operator boolean tidak profesional. Tapi saya setuju tentang nilai kode yang dapat dibaca, saya pasti akan membungkusnya dalam fungsi yang ditandai dengan jelas. Dan itulah yang dilakukan oleh sebagian besar kerangka kerja JS utama.
okdewit
79

Inilah implementasi JavaScript 1.6 yang kompatibel dari Array.indexOf:

if (!Array.indexOf) {
    Array.indexOf = [].indexOf ?
        function(arr, obj, from) {
            return arr.indexOf(obj, from);
        } :
        function(arr, obj, from) { // (for IE6)
            var l = arr.length,
                i = from ? parseInt((1 * from) + (from < 0 ? l : 0), 10) : 0;
            i = i < 0 ? 0 : i;
            for (; i < l; i++) {
                if (i in arr && arr[i] === obj) {
                    return i;
                }
            }
            return -1;
        };
}
Már Örlygsson
sumber
Ini terlihat hebat, tetapi sedikit bingung: * Bukankah tes pada baris 1 dan 3 setara? * Bukankah lebih baik untuk menguji prototipe, dan menambahkan fungsi ke Array.prototype jika perlu?
Avi Flax
10
Mereka tidak equvialent. [].indexOfadalah singkatan untuk Array.prototype.indexOf. Kami programmer Javascript paranoid-defensif menghindari memperluas prototipe asli di semua biaya.
Már Örlygsson
1
Bukankah [].indexOfmembuat array baru lalu mengakses indexOf, sementara Array.prototype.indexOfhanya mengakses prototipe secara langsung?
alex
3
@ alex ya [].indexOf === Array.prototype.indexOf(coba di FireBug), tetapi sebaliknya [].indexOf !== Array.indexOf.
Már Örlygsson
57

Menggunakan:

function isInArray(array, search)
{
    return array.indexOf(search) >= 0;
}

// Usage
if(isInArray(my_array, "my_value"))
{
    //...
}
Matías Cánepa
sumber
25
x ? true : falsebiasanya berlebihan. Ini di sini.
Ry-
@minitech Kenapa Anda bilang itu mubazir?
Matías Cánepa
8
array.indexOf(search) >= 0sudah menjadi boolean. Adil return array.indexOf(search) >= 0.
Ry-
@minitech, terima kasih! Sebenarnya saya tidak tahu bahwa konstruksi seperti itu dapat dikembalikan. TIL sesuatu yang baru.
Matías Cánepa
Secara harfiah setiap konstruksi dalam javascript dapat dikembalikan
BT
49

Memperluas Arrayobjek JavaScript adalah ide yang sangat buruk karena Anda memperkenalkan properti baru (metode khusus Anda) ke dalam for-inloop yang dapat memecah skrip yang ada. Beberapa tahun yang lalu penulis Prototipe perpustakaan harus merekayasa ulang implementasi perpustakaan mereka untuk menghapus hal semacam ini.

Jika Anda tidak perlu khawatir tentang kompatibilitas dengan JavaScript lain yang berjalan di halaman Anda, coba, jika tidak, saya akan merekomendasikan solusi fungsi berdiri bebas yang lebih aneh, tapi lebih aman.

Peter Mortensen
sumber
22
Saya tidak setuju. Loop for-in tidak boleh digunakan untuk array karena alasan ini. Menggunakan for-in loop akan pecah ketika menggunakan salah satu perpustakaan js populer
Tomas
Apakah ini dianggap tambalan monyet? lol Beberapa orang seperti itu.
cbmeeks
33

Satu-liner:

function contains(arr, x) {
    return arr.filter(function(elem) { return elem == x }).length > 0;
}
Sendiri
sumber
8
array.filter(e=>e==x).length > 0setara dengan array.some(e=>e==x)tetapi somelebih efisien
Apolo
28

Saya menggunakan yang berikut ini:

Array.prototype.contains = function (v) {
    return this.indexOf(v) > -1;
}

var a = [ 'foo', 'bar' ];

a.contains('foo'); // true
a.contains('fox'); // false
Eduardo Cuomo
sumber
24
function contains(a, obj) {
    return a.some(function(element){return element == obj;})
}

Array.prototype.some () ditambahkan ke standar ECMA-262 di edisi ke-5

dansalmo
sumber
jika menggunakan es6 daripada itu dapat contains = (a, obj) => a.some((element) => element === obj))
dipersingkat
Bahkan IE9 memiliki dukungan untuk Array.prototype.some () pada ECMAScript 5 .
Suncat2000
19

Dua arah indexOf/ lastIndexOfalternatif semoga lebih cepat

2015

Meskipun metode baru termasuk sangat bagus, dukungan pada dasarnya nol untuk saat ini.

Sudah lama saya memikirkan cara untuk mengganti fungsi indexOf / lastIndexOf yang lambat.

Cara performan telah ditemukan, dengan melihat jawaban teratas. Dari yang saya pilih containsfungsi diposting oleh @Damir Zekic yang seharusnya menjadi yang tercepat. Tapi itu juga menyatakan bahwa tolok ukur berasal dari 2008 dan sudah usang.

Saya juga lebih suka whilelebih for, tetapi karena tidak alasan tertentu saya berakhir menulis fungsi dengan untuk loop. Bisa juga dilakukan dengan awhile -- .

Saya ingin tahu apakah iterasi jauh lebih lambat jika saya memeriksa kedua sisi array saat melakukannya. Tampaknya tidak, dan fungsi ini sekitar dua kali lebih cepat daripada yang terpilih. Jelas itu juga lebih cepat daripada yang asli. Ini di lingkungan dunia nyata, di mana Anda tidak pernah tahu apakah nilai yang Anda cari ada di awal atau di akhir array.

Ketika Anda tahu Anda baru saja mendorong array dengan sebuah nilai, menggunakan lastIndexOf mungkin merupakan solusi terbaik, tetapi jika Anda harus melakukan perjalanan melalui array besar dan hasilnya bisa di mana-mana, ini bisa menjadi solusi yang solid untuk membuat segalanya lebih cepat.

Bidirectional indexOf / lastIndexOf

function bidirectionalIndexOf(a, b, c, d, e){
  for(c=a.length,d=c*1; c--; ){
    if(a[c]==b) return c; //or this[c]===b
    if(a[e=d-1-c]==b) return e; //or a[e=d-1-c]===b
  }
  return -1
}

//Usage
bidirectionalIndexOf(array,'value');

Uji kinerja

http://jsperf.com/bidirectionalindexof

Sebagai tes saya membuat array dengan entri 100 ribu.

Tiga pertanyaan: di awal, di tengah & di akhir array.

Saya harap Anda juga menemukan ini menarik dan menguji kinerjanya.

Catatan: Seperti yang Anda lihat saya sedikit memodifikasi containsfungsi untuk mencerminkan indexOf & lastIndexOf output (jadi pada dasarnya truedengan indexdan falsedengan -1). Itu seharusnya tidak merusaknya.

Varian prototipe array

Object.defineProperty(Array.prototype,'bidirectionalIndexOf',{value:function(b,c,d,e){
  for(c=this.length,d=c*1; c--; ){
    if(this[c]==b) return c; //or this[c]===b
    if(this[e=d-1-c] == b) return e; //or this[e=d-1-c]===b
  }
  return -1
},writable:false, enumerable:false});

// Usage
array.bidirectionalIndexOf('value');

Fungsi ini juga dapat dengan mudah dimodifikasi untuk mengembalikan true atau false atau bahkan objek, string atau apa pun itu.

Dan inilah whilevariannya:

function bidirectionalIndexOf(a, b, c, d){
  c=a.length; d=c-1;
  while(c--){
    if(b===a[c]) return c;
    if(b===a[d-c]) return d-c;
  }
  return c
}

// Usage
bidirectionalIndexOf(array,'value');

Bagaimana ini mungkin?

Saya pikir perhitungan sederhana untuk mendapatkan indeks yang direfleksikan dalam array sangat sederhana sehingga dua kali lebih cepat daripada melakukan iterasi loop yang sebenarnya.

Berikut ini adalah contoh kompleks yang melakukan tiga pemeriksaan per iterasi, tetapi ini hanya mungkin dilakukan dengan perhitungan yang lebih lama yang menyebabkan pelambatan kode.

http://jsperf.com/bidirectionalindexof/2

cocco
sumber
18

Performa

Hari ini 2020.01.07 saya melakukan tes pada MacOs HighSierra 10.13.6 di Chrome v78.0.0, Safari v13.0.4 dan Firefox v71.0.0 untuk 15 solusi yang dipilih. Kesimpulan

  • solusi berdasarkan JSON, Setdan secara mengejutkan find(K, N, O) paling lambat di semua browser
  • ES6 includes(F) hanya cepat pada chrome
  • solusi berdasarkan for (C, D) dan indexOf(G, H) cukup cepat pada semua browser pada array kecil dan besar jadi mungkin mereka adalah pilihan terbaik untuk solusi yang efisien
  • solusi penurunan indeks selama loop, (B) lebih lambat mungkin karena cara cache CPU bekerja .
  • Saya juga menjalankan tes untuk array besar ketika elemen yang dicari berada pada posisi 66% dari panjang array, dan solusi berdasarkan for(C, D, E) memberikan hasil yang sama (~ 630 ops / detik - tetapi E pada safari dan firefox adalah 10- 20% lebih lambat dari C dan D)

Hasil

masukkan deskripsi gambar di sini

Detail

Saya melakukan 2 tes kasus: untuk array dengan 10 elemen, dan array dengan 1 juta elemen. Dalam kedua kasus kami menempatkan elemen yang dicari di tengah array.

Array kecil - 10 elemen

Anda dapat melakukan tes di mesin Anda DI SINI

masukkan deskripsi gambar di sini

Array besar - 1.000.000 elemen

Anda dapat melakukan tes di mesin Anda DI SINI

masukkan deskripsi gambar di sini

Kamil Kiełczewski
sumber
16

Jika Anda menggunakan JavaScript 1.6 atau lebih baru (Firefox 1.5 atau lebih baru) Anda dapat menggunakan Array.indexOf . Kalau tidak, saya pikir Anda akan berakhir dengan sesuatu yang mirip dengan kode asli Anda.

Andru Luvisi
sumber
16
function inArray(elem,array)
{
    var len = array.length;
    for(var i = 0 ; i < len;i++)
    {
        if(array[i] == elem){return i;}
    }
    return -1;
} 

Mengembalikan indeks array jika ditemukan, atau -1 jika tidak ditemukan

LmC
sumber
16

Kami menggunakan cuplikan ini (berfungsi dengan objek, array, string):

/*
 * @function
 * @name Object.prototype.inArray
 * @description Extend Object prototype within inArray function
 *
 * @param {mix}    needle       - Search-able needle
 * @param {bool}   searchInKey  - Search needle in keys?
 *
 */
Object.defineProperty(Object.prototype, 'inArray',{
    value: function(needle, searchInKey){

        var object = this;

        if( Object.prototype.toString.call(needle) === '[object Object]' || 
            Object.prototype.toString.call(needle) === '[object Array]'){
            needle = JSON.stringify(needle);
        }

        return Object.keys(object).some(function(key){

            var value = object[key];

            if( Object.prototype.toString.call(value) === '[object Object]' || 
                Object.prototype.toString.call(value) === '[object Array]'){
                value = JSON.stringify(value);
            }

            if(searchInKey){
                if(value === needle || key === needle){
                return true;
                }
            }else{
                if(value === needle){
                    return true;
                }
            }
        });
    },
    writable: true,
    configurable: true,
    enumerable: false
});

Pemakaian:

var a = {one: "first", two: "second", foo: {three: "third"}};
a.inArray("first");          //true
a.inArray("foo");            //false
a.inArray("foo", true);      //true - search by keys
a.inArray({three: "third"}); //true

var b = ["one", "two", "three", "four", {foo: 'val'}];
b.inArray("one");         //true
b.inArray('foo');         //false
b.inArray({foo: 'val'})   //true
b.inArray("{foo: 'val'}") //false

var c = "String";
c.inArray("S");        //true
c.inArray("s");        //false
c.inArray("2", true);  //true
c.inArray("20", true); //false
dr.dimitru
sumber
15

Jika Anda memeriksa berulang kali untuk keberadaan suatu objek dalam array Anda mungkin harus melihat ke dalamnya

  1. Menjaga agar array diurutkan setiap saat dengan melakukan sortasi pada array Anda (letakkan objek baru di tempat yang tepat)
  2. Buat memperbarui objek sebagai menghapus operasi + insert yang diurutkan dan
  3. Gunakan pencarian pencarian biner di blog Anda contains(a, obj).
Ztyx
sumber
2
Atau jika mungkin, berhentilah menggunakan Array seluruhnya, dan alih-alih gunakan Obyek sebagai kamus, seperti yang disarankan oleh MattMcKnight dan ninjagecko.
joeytwiddle
13

Solusi yang bekerja di semua browser modern:

function contains(arr, obj) {
  const stringifiedObj = JSON.stringify(obj); // Cache our object to not call `JSON.stringify` on every iteration
  return arr.some(item => JSON.stringify(item) === stringifiedObj);
}

Pemakaian:

contains([{a: 1}, {a: 2}], {a: 1}); // true

Solusi IE6 +:

function contains(arr, obj) {
  var stringifiedObj = JSON.stringify(obj)
  return arr.some(function (item) {
    return JSON.stringify(item) === stringifiedObj;
  });
}

// .some polyfill, not needed for IE9+
if (!('some' in Array.prototype)) {
  Array.prototype.some = function (tester, that /*opt*/) {
    for (var i = 0, n = this.length; i < n; i++) {
      if (i in this && tester.call(that, this[i], i, this)) return true;
    } return false;
  };
}

Pemakaian:

contains([{a: 1}, {a: 2}], {a: 1}); // true

Mengapa harus menggunakan JSON.stringify?

Array.indexOfdan Array.includes(juga sebagian besar jawaban di sini) hanya membandingkan dengan referensi dan bukan dengan nilai.

[{a: 1}, {a: 2}].includes({a: 1});
// false, because {a: 1} is a new object

Bonus

ES6 satu-liner yang tidak dioptimalkan:

[{a: 1}, {a: 2}].some(item => JSON.stringify(item) === JSON.stringify({a: 1));
// true

Catatan: Membandingkan objek berdasarkan nilai akan bekerja lebih baik jika kunci berada dalam urutan yang sama, jadi agar aman Anda dapat mengurutkan kunci terlebih dahulu dengan paket seperti ini: https://www.npmjs.com/package/sort-keys


Memperbarui containsfungsi dengan optimasi perf. Terima kasih, keuangan karena menunjukkannya.

Igor Barbashin
sumber
Potongan kode khusus ini dapat bekerja di IE6 (belum diuji), tetapi IE tidak mendukung ES5 sampai IE9.
Mark Reed
Untuk alasan kinerja, Anda harus menghindari pengerasan. Paling tidak Anda harus menghindari JSON. Perintahkan "obj" pada setiap loop karena mahal dan akan memperlambat aplikasi Anda. Oleh karena itu Anda harus menangkapnya sebelum for-loop dalam variabel temp
itinance
1
@ Poin bagus. Memperbarui includesfungsi dengan saran Anda. Saya telah menjalankan jsperf dengan fungsi saya. Ini sekitar 5x lebih lambat dari termasuk lodash. Meskipun lodash tidak membandingkan dengan nilai dan tidak dapat menemukan {a: 1}di [{a: 1}]. Saya tidak tahu apakah ada perpustakaan yang melakukannya. Tapi saya ingin tahu apakah ada lebih banyak pemain dan tidak rumit cara melakukannya.
Igor Barbashin
Catatan akhir: ini tidak berfungsi dengan, katakanlah, contains([{ a: 1, b: 2 }], { b: 2, a: 1 })karena objek yang dirangkai mempertahankan urutan properti.
Monyet
1
@HereticMonkey, benar. Itu sebabnya saya menambahkan sort-keyscatatan di bagian bawah
Igor Barbashin
12

Gunakan beberapa fungsi lodash .

Ini ringkas, akurat dan memiliki dukungan lintas platform yang hebat.

Jawaban yang diterima bahkan tidak memenuhi persyaratan.

Persyaratan: Rekomendasikan cara yang paling ringkas dan efisien untuk mencari tahu apakah array JavaScript berisi objek.

Jawaban yang diterima:

$.inArray({'b': 2}, [{'a': 1}, {'b': 2}])
> -1

Rekomendasi saya:

_.some([{'a': 1}, {'b': 2}], {'b': 2})
> true

Catatan:

$ .inArray berfungsi dengan baik untuk menentukan apakah nilai skalar ada dalam array skalar ...

$.inArray(2, [1,2])
> 1

... tetapi pertanyaannya dengan jelas meminta cara yang efisien untuk menentukan apakah suatu objek terdapat dalam array.

Untuk menangani skalar dan objek, Anda bisa melakukan ini:

(_.isObject(item)) ? _.some(ary, item) : (_.indexOf(ary, item) > -1)
l3x
sumber
10

ECMAScript 6 memiliki proposal pencarian yang elegan.

Metode find mengeksekusi fungsi callback sekali untuk setiap elemen yang ada di dalam array sampai menemukan satu di mana callback mengembalikan nilai sebenarnya. Jika elemen tersebut ditemukan, cari segera mengembalikan nilai elemen itu. Kalau tidak, temukan pengembalian yang tidak ditentukan. callback dipanggil hanya untuk indeks array yang telah menetapkan nilai; itu tidak dipanggil untuk indeks yang telah dihapus atau yang tidak pernah diberi nilai.

Berikut adalah dokumentasi MDN tentang hal itu.

Fungsionalitas find berfungsi seperti ini.

function isPrime(element, index, array) {
    var start = 2;
    while (start <= Math.sqrt(element)) {
        if (element % start++ < 1) return false;
    }
    return (element > 1);
}

console.log( [4, 6, 8, 12].find(isPrime) ); // Undefined, not found
console.log( [4, 5, 8, 12].find(isPrime) ); // 5

Anda dapat menggunakan ini di ECMAScript 5 dan di bawahnya dengan mendefinisikan fungsi .

if (!Array.prototype.find) {
  Object.defineProperty(Array.prototype, 'find', {
    enumerable: false,
    configurable: true,
    writable: true,
    value: function(predicate) {
      if (this == null) {
        throw new TypeError('Array.prototype.find called on null or undefined');
      }
      if (typeof predicate !== 'function') {
        throw new TypeError('predicate must be a function');
      }
      var list = Object(this);
      var length = list.length >>> 0;
      var thisArg = arguments[1];
      var value;

      for (var i = 0; i < length; i++) {
        if (i in list) {
          value = list[i];
          if (predicate.call(thisArg, value, i, list)) {
            return value;
          }
        }
      }
      return undefined;
    }
  });
}
Pradeep Mahdevu
sumber
Ini sekarang menjadi standar: ecma-international.org/ecma-262/6.0/#sec-array.prototype.find
Madbreaks
9

Meskipun array.indexOf(x)!=-1merupakan cara paling ringkas untuk melakukan ini (dan telah didukung oleh browser non-Internet Explorer selama lebih dari satu dekade ...), itu bukan O (1), melainkan O (N), yang mengerikan. Jika array Anda tidak akan berubah, Anda dapat mengubah array Anda menjadi hashtable, lalu lakukan table[x]!==undefinedatau ===undefined:

Array.prototype.toTable = function() {
    var t = {};
    this.forEach(function(x){t[x]=true});
    return t;
}

Demo:

var toRemove = [2,4].toTable();
[1,2,3,4,5].filter(function(x){return toRemove[x]===undefined})

(Sayangnya, saat Anda dapat membuat Array.prototype.contain untuk "membekukan" array dan menyimpan hashtable di this._cache dalam dua baris, ini akan memberikan hasil yang salah jika Anda memilih untuk mengedit array Anda nanti. JavaScript memiliki kait yang tidak cukup untuk biarkan Anda mempertahankan status ini, tidak seperti Python misalnya.)

ninjagecko
sumber
9

Satu dapat menggunakan Set yang memiliki metode "has ()":

function contains(arr, obj) {
      var proxy = new Set(arr);
      if (proxy.has(obj))
        return true;
      else
        return false;
    }

    var arr = ['Happy', 'New', 'Year'];
    console.log(contains(arr, 'Happy'));

rlib
sumber
5
Saya pikir return proxy.has(obj)ini jauh lebih bersih daripada dua baris dengan pernyataan if-else di sini
Maciej Bukowski
function contains(arr, obj) { return new Set(arr).has(obj); }
Gordon Bean
8

Menggunakan:

var myArray = ['yellow', 'orange', 'red'] ;

alert(!!~myArray.indexOf('red')); //true

Demo

Untuk mengetahui apa yang tilde ~harus dilakukan pada saat ini, lihat pertanyaan ini Apa yang dilakukan tilde ketika mendahului ekspresi? .

Mina Gabriel
sumber
5
Ini sudah diposting setengah tahun yang lalu tidak perlu mengulanginya.
Shadow Wizard adalah Ear For You
3
Sebenarnya, itu belum diposting. Bukan sebagai jawaban, tetapi sebagai komentar atas jawaban, dan itupun tidak jelas dan ringkas. Terima kasih telah mempostingnya, Mina Gabriel.
T.CK
6

Oke, Anda bisa mengoptimalkan kode Anda untuk mendapatkan hasilnya!

Ada banyak cara untuk melakukan ini yang lebih bersih dan lebih baik, tetapi saya hanya ingin mendapatkan pola Anda dan menerapkannya dengan menggunakan JSON.stringify, cukup lakukan sesuatu seperti ini dalam kasus Anda:

function contains(a, obj) {
    for (var i = 0; i < a.length; i++) {
        if (JSON.stringify(a[i]) === JSON.stringify(obj)) {
            return true;
        }
    }
    return false;
}
Alireza
sumber
Catatan akhir: ini tidak berfungsi dengan, katakanlah, contains([{ a: 1, b: 2 }], { b: 2, a: 1 })karena objek yang dirangkai mempertahankan urutan properti.
Monyet
5

Bukan berarti yang terbaik, tetapi saya hanya menjadi kreatif dan menambah repertoar.

Jangan gunakan ini

Object.defineProperty(Array.prototype, 'exists', {
  value: function(element, index) {

    var index = index || 0

    return index === this.length ? -1 : this[index] === element ? index : this.exists(element, ++index)
  }
})


// Outputs 1
console.log(['one', 'two'].exists('two'));

// Outputs -1
console.log(['one', 'two'].exists('three'));

console.log(['one', 'two', 'three', 'four'].exists('four'));

sqram
sumber
Apa yang harus Anda gunakan jika tidak ini?
bryc
@ bryc mungkin solusi yang diterima, atau solusi lain dari sini. Jika Anda tidak terlalu peduli untuk kinerja, daripada Anda dapat menggunakan ini
sqram
5

Terkejut bahwa pertanyaan ini masih belum memiliki sintaks terbaru yang ditambahkan, menambahkan 2 sen saya.

Katakanlah kita memiliki array Objects arrObj dan kami ingin mencari objek di dalamnya.

Array.prototype. indexOf -> ( indeks pengembalian atau -1 ) umumnya digunakan untuk menemukan indeks elemen dalam array. Ini juga dapat digunakan untuk mencari objek tetapi hanya berfungsi jika Anda memberikan referensi ke objek yang sama.

let obj = { name: 'Sumer', age: 36 };
let arrObj = [obj, { name: 'Kishor', age: 46 }, { name: 'Rupen', age: 26 }];


console.log(arrObj.indexOf(obj));// 0
console.log(arrObj.indexOf({ name: 'Sumer', age: 36 })); //-1

console.log([1, 3, 5, 2].indexOf(2)); //3

Array.prototype. termasuk -> (mengembalikan benar atau salah )

console.log(arrObj.includes(obj));  //true
console.log(arrObj.includes({ name: 'Sumer', age: 36 })); //false

console.log([1, 3, 5, 2].includes(2)); //true

Array.prototype. find -> (mengambil callback, mengembalikan nilai / objek pertama yang mengembalikan true dalam CB).

console.log(arrObj.find(e => e.age > 40));  //{ name: 'Kishor', age: 46 }
console.log(arrObj.find(e => e.age > 40)); //{ name: 'Kishor', age: 46 }

console.log([1, 3, 5, 2].find(e => e > 2)); //3

Array.prototype. findIndex -> (mengambil callback, mengembalikan indeks nilai pertama / objek yang mengembalikan true dalam CB).

console.log(arrObj.findIndex(e => e.age > 40));  //1
console.log(arrObj.findIndex(e => e.age > 40)); //1

console.log([1, 3, 5, 2].findIndex(e => e > 2)); //1

Karena menemukan dan menemukanIndex menerima panggilan balik, kita dapat mengambil objek apa pun (bahkan jika kita tidak memiliki referensi) dari array dengan secara kreatif mengatur kondisi sebenarnya.

Sumer
sumber
5

Solusi sederhana untuk persyaratan ini digunakan find()

Jika Anda memiliki berbagai objek seperti di bawah ini,

var users = [{id: "101", name: "Choose one..."},
{id: "102", name: "shilpa"},
{id: "103", name: "anita"},
{id: "104", name: "admin"},
{id: "105", name: "user"}];

Kemudian Anda dapat memeriksa apakah objek dengan nilai Anda sudah ada atau belum

let data = users.find(object => object['id'] === '104');

jika data nol maka tidak ada admin, selain itu akan mengembalikan objek yang ada seperti di bawah ini.

{id: "104", name: "admin"}

Kemudian Anda dapat menemukan indeks objek itu dalam array dan mengganti objek menggunakan kode di bawah ini.

let indexToUpdate = users.indexOf(data);
let newObject = {id: "104", name: "customer"};
users[indexToUpdate] = newObject;//your new object
console.log(users);

Anda akan mendapatkan nilai seperti di bawah ini

[{id: "101", name: "Choose one..."},
{id: "102", name: "shilpa"},
{id: "103", name: "anita"},
{id: "104", name: "customer"},
{id: "105", name: "user"}];

Semoga ini bisa membantu siapa saja.

Siwa
sumber
5

    function countArray(originalArray) {
     
    	var compressed = [];
    	// make a copy of the input array
    	var copyArray = originalArray.slice(0);
     
    	// first loop goes over every element
    	for (var i = 0; i < originalArray.length; i++) {
     
    		var count = 0;	
    		// loop over every element in the copy and see if it's the same
    		for (var w = 0; w < copyArray.length; w++) {
    			if (originalArray[i] == copyArray[w]) {
    				// increase amount of times duplicate is found
    				count++;
    				// sets item to undefined
    				delete copyArray[w];
    			}
    		}
     
    		if (count > 0) {
    			var a = new Object();
    			a.value = originalArray[i];
    			a.count = count;
    			compressed.push(a);
    		}
    	}
     
    	return compressed;
    };
    
    // It should go something like this:
    
    var testArray = new Array("dog", "dog", "cat", "buffalo", "wolf", "cat", "tiger", "cat");
    var newArray = countArray(testArray);
    console.log(newArray);

Sanjay Magar
sumber