Apa yang paling ringkas dan efisien cara mengetahui jika JavaScript array berisi nilai?
Ini adalah satu-satunya cara yang 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 yang lebih baik dan lebih ringkas cara untuk mencapai hal ini?
Hal ini sangat berkaitan erat dengan Stack Overflow pertanyaan cara Terbaik untuk menemukan item dalam JavaScript Array? alamat yang menemukan benda-benda dalam array menggunakan indexOf
.
Saat ini browser yang memiliki Array#termasuk
, yang tidak persis bahwa, ini banyak didukung, dan memiliki polyfill untuk browser lama.
> ['joe', 'jane', 'mary'].includes('jane');
true
Anda juga dapat menggunakan Array#indexOf
, yang kurang langsung, tapi doesn't membutuhkan Polyfills untuk out of date browser.
jQuery menawarkan $.inArray
, yang secara fungsional setara dengan Array#indexOf
.
underscore.js, sebuah utilitas JavaScript library, menawarkan _.berisi(daftar nilai)
, alias _.termasuk(daftar nilai)
, baik yang menggunakan indexOf secara internal jika melewati JavaScript array.
Beberapa framework lain menawarkan metode yang serupa:
dojo.indexOf(array, nilai, [fromIndex, findLast])
array.indexOf(nilai)
array.indexOf(nilai)
findValue(array, nilai)
array.indexOf(nilai)
Ext.Array.berisi(array, nilai)
_.termasuk(array, nilai, [dari])
(adalah _.berisi
sebelum 4.0.0)R. meliputi(nilai array)
array.termasuk(nilai)
Perhatikan bahwa beberapa kerangka menerapkan ini sebagai fungsi, sementara yang lain menambahkan fungsi untuk array prototipe.
Update dari 2019: Ini jawaban dari 2008 (11 tahun!) dan tidak relevan untuk modern JS penggunaan. Dijanjikan peningkatan kinerja didasarkan pada benchmark yang dilakukan di browser waktu itu. Ini mungkin tidak relevan dengan modern JS eksekusi konteks. Jika anda membutuhkan solusi yang mudah, mencari jawaban yang lain. Jika anda membutuhkan performa terbaik, patokan untuk diri sendiri dalam relevan eksekusi lingkungan.
Seperti yang dikatakan orang lain, iterasi melalui array adalah mungkin cara terbaik, tapi itu terbukti bahwa penurunan sementara
loop adalah cara tercepat untuk iterate dalam JavaScript. Jadi, anda mungkin ingin menulis ulang kode sebagai berikut:
function contains(a, obj) {
var i = a.length;
while (i--) {
if (a[i] === obj) {
return true;
}
}
return false;
}
Tentu saja, anda mungkin juga memperpanjang Array prototipe:
Array.prototype.contains = function(obj) {
var i = this.length;
while (i--) {
if (this[i] === obj) {
return true;
}
}
return false;
}
Dan sekarang anda hanya dapat menggunakan berikut:
alert([1, 2, 3].contains(2)); // => true
alert([1, 2, 3].contains('2')); // => false
indexOf
mungkin, tapi itu's "JavaScript ekstensi ke ECMA-262 standar; karena itu tidak dapat hadir dalam implementasi lain dari standar."
Contoh:
[1, 2, 3].indexOf(1) => 0
["foo", "bar", "baz"].indexOf("bar") => 1
[1, 2, 3].indexOf(4) => -1
AFAICS Microsoft tidak tidak menawarkan beberapa jenis alternatif untuk ini, tetapi anda dapat menambahkan fungsionalitas mirip dengan array di Internet Explorer (dan browser lain yang don't dukungan indexOf
) jika anda ingin, sebagai cepat pencarian Google mengungkapkan (misalnya, ini).
ECMAScript 7 memperkenalkan Array.prototipe.termasuk
.
Hal ini dapat digunakan seperti ini:
[1, 2, 3].includes(2); // true
[1, 2, 3].includes(4); // false
Hal ini juga menerima opsional kedua argumen fromIndex
:
[1, 2, 3].includes(3, 3); // false
[1, 2, 3].includes(3, -1); // true
Tidak seperti indexOf
, yang menggunakan Ketat Kesetaraan Perbandingan, termasuk
dibandingkan menggunakan SameValueZero persamaan algoritma. Yang berarti bahwa anda dapat mendeteksi jika sebuah array termasuk NaN
:
[1, 2, NaN].includes(NaN); // true
Juga tidak seperti indexOf
, termasuk
tidak melewatkan hilang indeks:
new Array(5).includes(undefined); // true
Saat itu's masih draft, tapi dapat polyfilled untuk membuatnya bekerja pada semua browser.
Atas jawaban menganggap tipe primitif tetapi jika anda ingin mengetahui jika array berisi obyek dengan beberapa sifat, Array.prototipe.beberapa() adalah sebuah 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
Hal yang baik tentang itu adalah bahwa iterasi dibatalkan setelah unsur ini ditemukan jadi tidak perlu iterasi siklus terhindar.
Juga, itu cocok dengan baik dalam sebuah pernyataan if
sejak itu mengembalikan boolean:
if (items.some(item => item.a === '3')) {
// do something
}
* Sebagai jamess kemukakan dalam komentar, pada saat jawaban ini, September 2018, Array.prototipe.beberapa()
adalah sepenuhnya didukung: caniuse.com dukungan table
Berikut ini's JavaScript 1.6 kompatibel pelaksanaan 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;
};
}
Memperpanjang JavaScript Array
objek adalah benar-benar ide yang buruk karena anda memperkenalkan sifat-sifat baru (custom metode) ke bagi-in
loop yang dapat mematahkan skrip yang sudah ada. Beberapa tahun yang lalu penulis Prototype perpustakaan harus re-engineer mereka implementasi perpustakaan untuk menghapus hanya hal-hal semacam ini.
Jika anda don't perlu khawatir tentang kompatibilitas dengan JavaScript yang berjalan pada halaman anda, pergi untuk itu, jika tidak, aku'd merekomendasikan lebih canggung, tapi lebih aman gratis-fungsi berdiri solusi.
Berpikir out of the box untuk kedua, jika anda membuat panggilan ini banyak banyak kali, hal ini jauh lebih efisien untuk menggunakan <menyerang>array asosiatif</strike> Peta untuk melakukan pencarian dengan menggunakan fungsi hash.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map
Yang mudah-mudahan lebih cepat dua arah indexOf
/ lastIndexOf
alternatif
Sedangkan metode baru termasuk ini sangat bagus, dukungan pada dasarnya adalah nol untuk saat ini.
It's waktu yang lama bahwa aku sedang memikirkan cara untuk mengganti lambat indexOf/lastIndexOf fungsi.
Sebuah performant cara telah ditemukan, melihat atas jawaban. Dari mereka saya memilih berisi
fungsi diposting oleh @Damir Zekic yang harus menjadi yang tercepat. Tapi hal ini juga menyatakan bahwa tolok ukur dari tahun 2008 dan sudah ketinggalan jaman.
Saya juga lebih suka sementara
atas untuk
, tapi untuk alasan tertentu saya terakhir menulis fungsi dengan untuk loop. Bisa juga dilakukan dengan sementara --
.
Saya penasaran jika iterasi jauh lebih lambat jika saya memeriksa kedua sisi kenyamanan saat melakukan itu. Rupanya tidak ada, dan jadi fungsi ini adalah sekitar dua kali lebih cepat dari atas memilih orang-orang. Jelas itu's juga lebih cepat dari yang asli satu. Ini di lingkungan dunia nyata, di mana anda tidak pernah tahu jika nilai anda sedang mencari di awal atau di akhir dari array.
Ketika anda tahu bahwa anda hanya mendorong sebuah array dengan nilai, menggunakan lastIndexOf tetap mungkin solusi terbaik, tetapi jika anda harus melakukan perjalanan melalui besar array dan hasilnya bisa di mana-mana, ini bisa menjadi solusi yang solid untuk membuat hal-hal lebih cepat.
Dua arah 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');
http://jsperf.com/bidirectionalindexof
Sebagai uji coba saya membuat sebuah array dengan 100 ribu entri.
Tiga pertanyaan: di awal, di tengah & di akhir array.
Saya harap anda juga menemukan ini menarik dan tes kinerja.
Catatan: Seperti yang anda lihat saya sedikit dimodifikasi berisi
fungsi untuk mencerminkan indexOf & lastIndexOf output (jadi pada dasarnya benar
dengan index
dan palsu
dengan -1
). Yang seharusnya't membahayakan itu.
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 juga dapat dengan mudah dimodifikasi untuk mengembalikan true atau false atau bahkan objek, string, atau apapun itu.
Dan di sini adalah sementara
varian:
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');
Saya berpikir bahwa perhitungan sederhana untuk mendapatkan tercermin indeks dalam array adalah sangat sederhana yang's dua kali lebih cepat daripada melakukan yang sebenarnya loop iterasi.
Berikut ini adalah kompleks misalnya lakukan tiga pemeriksaan per iterasi, tapi ini hanya mungkin dengan perhitungan yang menyebabkan perlambatan kode.
Jika anda menggunakan JavaScript 1.6 atau yang lebih baru (Firefox 1.5 atau yang lebih baru), anda dapat menggunakan Array.indexOf. Jika tidak, saya pikir anda akan berakhir dengan sesuatu yang mirip untuk anda asli kode.
Jika anda memeriksa berulang kali untuk keberadaan sebuah objek dalam sebuah array, anda mungkin harus melihat ke
mengandung(a, obj)
.Kami menggunakan potongan ini (bekerja 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
});
Penggunaan:
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
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);
}
Penggunaan:
contains([{a: 1}, {a: 2}], {a: 1}); // true
IE6+ solusi:
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;
};
}
Penggunaan:
contains([{a: 1}, {a: 2}], {a: 1}); // true
JSON.stringify
?Array.indexOf
dan Array.termasuk
(serta sebagian dari jawaban di sini) hanya membandingkan dengan referensi dan bukan oleh nilai.
[{a: 1}, {a: 2}].includes({a: 1});
// false, because {a: 1} is a new object
Non-dioptimalkan ES6 satu-liner:
[{a: 1}, {a: 2}].some(item => JSON.stringify(item) === JSON.stringify({a: 1));
// true
Catatan: Membandingkan benda berdasarkan nilai akan bekerja lebih baik jika tombol dalam urutan yang sama, jadi untuk amannya anda mungkin semacam tombol pertama dengan paket seperti ini: https://www.npmjs.com/package/sort-keys
Diperbarui berisi
fungsi dengan perf optimasi. Terima kasih itinance untuk menunjuk keluar.
Gunakan lodash's beberapa fungsi.
It's ringkas, akurat dan memiliki dukungan lintas platform.
Jawaban yang diterima tidak memenuhi persyaratan.
Persyaratan: Merekomendasikan yang paling ringkas dan efisien cara mengetahui jika JavaScript array yang 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 bekerja dengan baik untuk menentukan apakah suatu skalar nilai yang ada dalam array skalar...
$.inArray(2, [1,2])
> 1
... tetapi pertanyaan dengan jelas meminta untuk cara yang efisien untuk menentukan apakah obyek yang terkandung dalam array.
Dalam rangka untuk menangani kedua skalar dan benda-benda, anda bisa melakukan hal ini:
(_.isObject(item)) ? _.some(ary, item) : (_.indexOf(ary, item) > -1)