Bagaimana menentukan apakah array Javascript berisi objek dengan atribut yang sama dengan nilai yang diberikan?

658

Saya memiliki array seperti

vendors = [
    {
      Name: 'Magenic',
      ID: 'ABC'
     },
    {
      Name: 'Microsoft',
      ID: 'DEF'
    } //and so on goes array... 
];

Bagaimana cara memeriksa array ini untuk melihat apakah Magenic ada? Saya tidak ingin mengulang, kecuali saya harus melakukannya. Saya sedang bekerja dengan beberapa ribu catatan yang berpotensi.


DIPERBARUI

Karena ini adalah posting yang populer, saya pikir saya akan membagikan sesuatu yang baru yang saya temukan. Dan tampaknya @CAFxX telah membagikan ini! Saya harus membaca ini lebih sering. Saya menemukan https://benfrain.com/understanding-native-javascript-array-methods/ .

vendors.filter(function(vendor){ return vendor.Name === "Magenic" })

Dan dengan ECMAScript 2015 bahkan lebih mudah menggunakan fungsi panah baru:

vendors.filter(vendor => vendor.Name === "Magenic")
David Lozzi
sumber
Maafkan komentar yang tampaknya acak, tetapi apakah pertanyaan Anda hanya tentang JSON atau hanya array JavaScript?
Alex Turpin
4
Solusi @CAFxX lebih baik, akan luar biasa jika Anda memperbarui solusi yang dipilih.
eMarine
1
Setuju, tidak melihat itu sebelumnya!
David Lozzi
Anda dapat menyederhanakan ini sekarang bahkan lebih dengan menggunakan fungsi panah. Semua browser modern mendukung ini dan terlihat lebih bagus.
Piotr Kula
Anda dapat menggunakan fungsi peta, sangat berguna
Monir alhussini

Jawaban:

264

Sunting 2018 : Jawaban ini dari 2011, sebelum browser secara luas mendukung metode penyaringan array dan fungsi panah. Silahkan lihat pada jawaban CAFxX ini .

Tidak ada cara "ajaib" untuk memeriksa sesuatu dalam array tanpa loop. Bahkan jika Anda menggunakan beberapa fungsi, fungsi itu sendiri akan menggunakan loop. Apa yang dapat Anda lakukan adalah keluar dari loop segera setelah Anda menemukan apa yang Anda cari untuk meminimalkan waktu komputasi.

var found = false;
for(var i = 0; i < vendors.length; i++) {
    if (vendors[i].Name == 'Magenic') {
        found = true;
        break;
    }
}
Alex Turpin
sumber
4
Tidak masalah. Perlu diingat bahwa solusi Keith juga sangat memungkinkan dan menyelamatkan Anda dari perulangan.
Alex Turpin
2
Anda tidak perlu bendera jika yang perlu Anda ketahui adalah ada atau tidaknya "sesuatu", Anda hanya dapat memeriksa nilai indeks pindai dengan ukuran array. Agar ini berfungsi, indeks var harus dideklarasikan sebelum pernyataan for for course.
Alex
5
Opsi ini tampaknya berfungsi sekarang: vendor.forEach, vendor.filter, vendor.reduce
David Lozzi
1
bagaimana dengan JSON.stringify (vendor) .indexOf ('Magenic')! == -1
Last Breath
1
@LastBreath yang dapat menghasilkan false positive dengan mudah jika 'Magenic'ada di tempat lain di objek
Alex Turpin
948

Tidak perlu menemukan kembali rodalingkaran, setidaknya tidak secara eksplisit (menggunakan fungsi panah , hanya browser modern ):

if (vendors.filter(e => e.Name === 'Magenic').length > 0) {
  /* vendors contains the element we're looking for */
}

atau, lebih baik lagi :

if (vendors.some(e => e.Name === 'Magenic')) {
  /* vendors contains the element we're looking for */
}

EDIT: Jika Anda memerlukan kompatibilitas dengan browser yang buruk maka taruhan terbaik Anda adalah:

if (vendors.filter(function(e) { return e.Name === 'Magenic'; }).length > 0) {
  /* vendors contains the element we're looking for */
}
CAFxX
sumber
4
@ Roket mengapa Anda mengedit jawaban saya? Sintaks tanpa kurung kurawal adalah javascript yang benar-benar valid .
CAFxX
4
Sintaks "lambda" masih tidak berfungsi di Chrome 16 (yang bukan browser yang buruk).
Rocket Hazmat
27
Tergantung pada definisi Anda tentang buruk, kurasa. Sintaks itu adalah bagian dari javascript 1.8.
CAFxX
7
The penutupan ekspresi yang Anda gunakan di sini di contoh pertama dan kedua memiliki non-standar, tidak menggunakan! peringatan dari Mozilla (lihat tautan itu). Mereka hanya pernah bekerja di Firefox, dan sekarang sudah usang dan akan dihapus demi fungsi panah .
doppelgreener
2
@ 7hibault karena somedapat korsleting sekali objek dengan name === "Magenic"ditemukan. Dengan filter, itu akan memeriksa setiap item sampai akhir array dan membuat item array baru yang cocok dengan kondisi, lalu periksalength
adiga
93

Tidak perlu loop. Tiga metode yang muncul di pikiran:

Array.prototype.some ()

Ini adalah jawaban paling tepat untuk pertanyaan Anda, yaitu "periksa apakah ada sesuatu", menyiratkan hasil bool. Ini akan benar jika ada benda 'Magenic', false jika tidak:

let hasMagenicVendor = vendors.some( vendor => vendor['Name'] === 'Magenic' )

Array.prototype.filter ()

Ini akan mengembalikan array dari semua objek 'Magenic', bahkan jika hanya ada satu (akan mengembalikan array satu elemen):

let magenicVendors = vendors.filter( vendor => vendor['Name'] === 'Magenic' )

Jika Anda mencoba memaksa ini ke boolean, itu tidak akan berfungsi, karena array kosong (tidak ada objek 'Magenic') masih benar. Jadi gunakan saja magenicVendors.lengthdalam kondisi Anda.

Array.prototype.find ()

Ini akan mengembalikan objek 'Magenic' pertama (atau undefinedjika tidak ada):

let magenicVendor = vendors.find( vendor => vendor['Name'] === 'Magenic' );

Ini memaksa boolean oke (objek apa pun adalah benar, undefinedsalah).


Catatan: Saya menggunakan vendor ["Nama"] alih-alih vendor. Nama karena casing aneh dari nama properti.

Catatan 2: Tidak ada alasan untuk menggunakan kesetaraan longgar (==) alih-alih kesetaraan yang ketat (===) saat memeriksa nama.

boxtrain
sumber
5
Ini berguna untuk menunjukkan bahwa di bawah tenda, ini semua adalah perulangan. Ini semua juga lebih lambat secara komputasional daripada sekadar untuk mengulang dan melakukan operasi.
ThePartyTurtle
Semoga berbagi cinta itu di sini: stackoverflow.com/questions/21748670/... jadi lebih banyak orang seperti saya tidak menavigasi ke halaman lama itu dan membuat asumsi.
ThePartyTurtle
43

Jawaban yang diterima masih berfungsi tetapi sekarang kami memiliki metode asli ECMAScript 6 [Array.find][1]untuk mencapai efek yang sama.

Mengutip MDN:

Metode find () mengembalikan nilai elemen pertama dalam array yang memenuhi fungsi pengujian yang disediakan. Kalau tidak, undefined dikembalikan.

var arr = []; 
var item = {
  id: '21',
  step: 'step2',
  label: 'Banana',
  price: '19$'
};

arr.push(item);
/* note : data is the actual object that matched search criteria 
  or undefined if nothing matched */
var data = arr.find( function( ele ) { 
    return ele.id === '21';
} );

if( data ) {
 console.log( 'found' );
 console.log(data); // This is entire object i.e. `item` not boolean
}

Lihat tautan jsfiddle saya. Ada polyfill untuk IE yang disediakan oleh mozilla

TeaCoder
sumber
2
Bisa jadi lebih pendek jika Anda baru saja melakukannya return ele.id == '2', tetapi memberi +1 untuk solusi ES6 yang baik.
Lye Fish
Bagus untuk mendapat jawaban segar :) Hanya ingin tahu apakah kinerja lebih baik atau tidak daripada jawaban di atas ...
Emidomenge
Saya pikir penting untuk menunjukkan bahwa nilai pengembalian 'data' (ketika ele.id cocok dengan id, seperti '21') akan menjadi item array itu sendiri (dalam hal ini, objek item keseluruhan). Jika harapannya adalah bahwa hasil variabel data akan menjadi 'benar' atau 'salah' daripada nilai palsu, Anda akan sangat kecewa.
adamgede
Terima kasih! Tugas saya agak berbeda. Dapatkan indeks Object di Array => di push if <0 || splice(index, 1)sini adalah kode saya yang sedikit diperbarui:const index = this.selected.indexOf(this.selected.find(s => s.id == passedObj.id))
Leonid Zadorozhnykh
30

Begini cara saya akan melakukannya

const found = vendors.some(item => item.Name === 'Magenic');

array.some()Metode memeriksa apakah ada setidaknya satu nilai dalam array yang cocok dengan kriteria dan mengembalikan boolean. Dari sini Anda dapat pergi dengan:

if (found) {
// do something
} else {
// do something else
}
Mirza Leka
sumber
22

Kecuali jika Anda ingin merestrukturisasi seperti ini:

vendors = {
    Magenic: {
      Name: 'Magenic',
      ID: 'ABC'
     },
    Microsoft: {
      Name: 'Microsoft',
      ID: 'DEF'
    } and so on... 
};

yang dapat Anda lakukan if(vendors.Magnetic)

Anda harus mengulang

Keith.Abramo
sumber
2
Jika dia masih ingin mempertahankan struktur objek untuk menggunakannya di tempat lain
Keith.Abramo
21

Sesuai spesifikasi ECMAScript 6, Anda dapat menggunakan findIndex.

const magenicIndex = vendors.findIndex(vendor => vendor.Name === 'Magenic');

magenicIndexakan menahan 0(yang merupakan indeks dalam array) atau -1jika tidak ditemukan.

Lucas Bento
sumber
Hanya untuk membuat orang sadar bahwa 0 akan tetap cocok sebagai hasil yang salah jika itu digunakan sebagai kondisi. Untuk alasan ini saya pikir find () lebih baik karena Anda mendapatkan evaluasi kebenaran yang lebih logis .
dhj
15

Karena OP telah mengajukan pertanyaan apakah kuncinya ada atau tidak .

Solusi yang lebih elegan yang akan mengembalikan boolean menggunakan fungsi pengurangan ES6

const magenicVendorExists =  vendors.reduce((accumulator, vendor) => (accumulator||vendor.Name === "Magenic"), false);

Catatan: Parameter awal pengurangan adalah a falsedan jika array memiliki kunci, itu akan mengembalikan true.

Semoga ini membantu untuk implementasi kode yang lebih baik dan lebih bersih

Jay Chakra
sumber
1
Sejak kapan !! [] sama dengan false?
Sergey
1
Tangkapan bagus. Jawaban yang diperbarui menggunakan pengurangan :)
Jay Chakra
1
Ini salah. Parameter pertama reduceadalah akumulator dan bukan vendorobjek. Ini memeriksa false.Name === "Magenic"setiap loop dan mengembalikan false
adiga
@ Adiga: Dikoreksi.
Jay Chakra
1
Silakan juga periksa solusi Mirza Leka. Solusi yang jauh lebih elegan.
Jay Chakra
13

Anda tidak bisa tanpa melihat ke objek sebenarnya.

Anda mungkin harus sedikit mengubah struktur Anda

vendors = {
    Magenic:   'ABC',
    Microsoft: 'DEF'
};

Maka Anda bisa menggunakannya seperti pencarian-hash.

vendors['Microsoft']; // 'DEF'
vendors['Apple']; // undefined
jandy
sumber
6

Mungkin sudah terlambat, tetapi array javascript memiliki dua metode somedan everymetode yang mengembalikan boolean dan dapat membantu Anda mencapainya.

Saya pikir someakan paling tepat untuk apa yang ingin Anda capai.

vendors.some( vendor => vendor['Name'] !== 'Magenic' )

Beberapa memvalidasi bahwa salah satu objek dalam array memenuhi kondisi yang diberikan.

vendors.every( vendor => vendor['Name'] !== 'Magenic' )

Setiap memvalidasi bahwa semua objek dalam array memenuhi kondisi yang diberikan.

Akinjiola Toni
sumber
Itu tidak berfungsi, const array1 = [{name:'Mike'},{name:'Alice'}]; console.log(array1.every(item => item.name !== 'Mike'));itu harus benar
Thanwa Ch.
Maaf sobat, maksud saya some, akan memperbarui jawaban saya.
Akinjiola Toni
5

Anda harus mengulang, tidak ada jalan lain.

function seekVendor(vendors, name) {
  for (var i=0, l=vendors.length; i<l; i++) {
    if (typeof vendors[i] == "object" && vendors[i].Name === name) {
      return vendors[i];
    }
  }
}

Tentu saja Anda bisa menggunakan perpustakaan seperti linq.js untuk menjadikan ini lebih menyenangkan:

Enumerable.From(vendors).Where("$.Name == 'Magenic'").First();

(lihat jsFiddle untuk demo)

Saya ragu linq.js akan lebih cepat daripada loop lurus ke depan, tetapi tentu saja lebih fleksibel ketika segala sesuatunya menjadi sedikit lebih rumit.

Tomalak
sumber
5

Menguji elemen array:

JS Menawarkan fungsi array yang memungkinkan Anda untuk mencapai hal ini dengan relatif mudah. Mereka adalah sebagai berikut:

  1. Array.prototype.filter: Mengambil fungsi panggilan balik yang merupakan tes, array kemudian diulang dengan panggilan balik dan difilter menurut panggilan balik ini. Array baru yang difilter dikembalikan.
  2. Array.prototype.some: Mengambil fungsi panggilan balik yang merupakan tes, array kemudian diulangi dengan panggilan balik dan jika ada elemen yang lulus tes, boolean true dikembalikan. Kalau tidak salah dikembalikan

Spesifik dijelaskan dengan baik melalui contoh:

Contoh:

vendors = [
    {
      Name: 'Magenic',
      ID: 'ABC'
     },
    {
      Name: 'Microsoft',
      ID: 'DEF'
    } //and so on goes array... 
];

// filter returns a new array, we instantly check if the length 
// is longer than zero of this newly created array
if (vendors.filter(company => company.Name === 'Magenic').length ) {
  console.log('I contain Magenic');
}

// some would be a better option then filter since it directly returns a boolean
if (vendors.some(company => company.Name === 'Magenic')) {
  console.log('I also contain Magenic');
}

Dukungan browser:

2 fungsi ini ES6berfungsi, tidak semua browser mungkin mendukungnya. Untuk mengatasinya Anda bisa menggunakan polyfill. Ini adalah polyfill untuk Array.prototype.some(dari MDN):

if (!Array.prototype.some) {
  Array.prototype.some = function(fun, thisArg) {
    'use strict';

    if (this == null) {
      throw new TypeError('Array.prototype.some called on null or undefined');
    }

    if (typeof fun !== 'function') {
      throw new TypeError();
    }

    var t = Object(this);
    var len = t.length >>> 0;

    for (var i = 0; i < len; i++) {
      if (i in t && fun.call(thisArg, t[i], i, t)) {
        return true;
      }
    }

    return false;
  };
}

Willem van der Veen
sumber
4

jika Anda menggunakan jquery, Anda dapat memanfaatkan grep untuk membuat array dengan semua objek yang cocok:

var results = $.grep(vendors, function (e) {
    return e.Name == "Magenic";
});

dan kemudian gunakan array hasil:

for (var i=0, l=results.length; i<l; i++) {
    console.log(results[i].ID);
}
Eitan
sumber
3

Perbaiki saya jika saya salah .. saya bisa menggunakan forEachmetode seperti ini,

var found=false;
vendors.forEach(function(item){
   if(item.name === "name"){
       found=true;

   }
});

Saat ini saya sudah terbiasa dengan itu, karena kesederhanaan dan kata yang jelas. Terima kasih.

Siddhesh Mishra
sumber
1
Catatan: tidak ada gunanya kembali ke sini
Edison
2

Anda dapat mencoba ini untuk saya.

const _ = require('lodash');

var arr = [
  {
    name: 'Jack',
    id: 1
  },
  {
    name: 'Gabriel',
    id: 2
  },
  {
    name: 'John',
    id: 3
  }
]

function findValue(arr,value) {
  return _.filter(arr, function (object) {
    return object['name'].toLowerCase().indexOf(value.toLowerCase()) >= 0;
  });
}

console.log(findValue(arr,'jack'))
//[ { name: 'Jack', id: 1 } ]
jenish
sumber
Yah ini adalah pertanyaan yang sangat lama dan saya pikir pembaruannya sudah memiliki solusi terbaik saat ini.
Federico Galfione
1

Anda bisa menggunakan lodash . Jika lodash library terlalu berat untuk aplikasi Anda, pertimbangkan untuk tidak menggunakan fungsi yang tidak perlu.

let newArray = filter(_this.props.ArrayOne, function(item) {
                    return find(_this.props.ArrayTwo, {"speciesId": item.speciesId});
                });

Ini hanya satu cara untuk melakukan ini. Yang lain bisa:

var newArray=  [];
     _.filter(ArrayOne, function(item) {
                        return AllSpecies.forEach(function(cItem){
                            if (cItem.speciesId == item.speciesId){
                            newArray.push(item);
                          }
                        }) 
                    });

console.log(arr);

Contoh di atas juga dapat ditulis ulang tanpa menggunakan perpustakaan seperti:

var newArray=  [];
ArrayOne.filter(function(item) {
                return ArrayTwo.forEach(function(cItem){
                    if (cItem.speciesId == item.speciesId){
                    newArray.push(item);
                  }
                }) 
            });
console.log(arr);

Semoga jawaban saya membantu.

Abhay Shiro
sumber
1

Banyak jawaban di sini baik dan sangat mudah. Tetapi jika array objek Anda memiliki set nilai yang tetap maka Anda dapat menggunakan trik di bawah ini:

Petakan semua nama dalam suatu objek.

vendors = [
    {
      Name: 'Magenic',
      ID: 'ABC'
     },
    {
      Name: 'Microsoft',
      ID: 'DEF'
    }
];

var dirtyObj = {}
for(var count=0;count<vendors.length;count++){
   dirtyObj[vendors[count].Name] = true //or assign which gives you true.
}

Sekarang dirtyObj ini dapat Anda gunakan berulang kali tanpa loop.

if(dirtyObj[vendor.Name]){
  console.log("Hey! I am available.");
}
jesusverma
sumber
1

Untuk membandingkan satu objek dengan yang lain, saya menggabungkan for in loop (digunakan untuk mengulang objek) dan some (). Anda tidak perlu khawatir tentang keluar array batas dll, sehingga menghemat beberapa kode. Dokumentasi tentang .beberapa dapat ditemukan di sini

var productList = [{id: 'text3'}, {id: 'text2'}, {id: 'text4', product: 'Shampoo'}]; // Example of selected products
var theDatabaseList = [{id: 'text1'}, {id: 'text2'},{id: 'text3'},{id:'text4', product: 'shampoo'}];    
var  objectsFound = [];

for(let objectNumber in productList){
    var currentId = productList[objectNumber].id;   
    if (theDatabaseList.some(obj => obj.id === currentId)) {
        // Do what you need to do with the matching value here
        objectsFound.push(currentId);
    }
}
console.log(objectsFound);

Cara alternatif saya membandingkan satu objek dengan yang lain adalah dengan menggunakan nested for loop dengan Object.keys (). Length untuk mendapatkan jumlah objek dalam array. Kode di bawah ini:

var productList = [{id: 'text3'}, {id: 'text2'}, {id: 'text4', product: 'Shampoo'}]; // Example of selected products
var theDatabaseList = [{id: 'text1'}, {id: 'text2'},{id: 'text3'},{id:'text4', product: 'shampoo'}];    
var objectsFound = [];

for(var i = 0; i < Object.keys(productList).length; i++){
        for(var j = 0; j < Object.keys(theDatabaseList).length; j++){
        if(productList[i].id === theDatabaseList[j].id){
            objectsFound.push(productList[i].id);
        }       
    }
}
console.log(objectsFound);

Untuk menjawab pertanyaan persis Anda, jika hanya mencari nilai dalam suatu objek, Anda bisa menggunakan satu untuk di dalam loop.

var vendors = [
    {
      Name: 'Magenic',
      ID: 'ABC'
     },
    {
      Name: 'Microsoft',
      ID: 'DEF'
    } 
];

for(var ojectNumbers in vendors){
    if(vendors[ojectNumbers].Name === 'Magenic'){
        console.log('object contains Magenic');
    }
}
Kida-kida
sumber
0

Atau Anda dapat melakukannya:

const find = (key, needle) => return !!~vendors.findIndex(v => (v[key] === needle));
BrunoWest
sumber
1
Anda sebaiknya mengatakan mengapa dia bisa melakukan itu
Azzabi Haythem
0

var without2 = (arr, args) => arr.filter(v => v.id !== args.id); Contoh:

without2([{id:1},{id:1},{id:2}],{id:2})

Hasil: tanpa2 ([{id: 1}, {id: 1}, {id: 2}], {id: 2})

behzad abbasi
sumber
Saya pikir Anda bermaksud mengatakan Hasil: [{id: 1}, {id: 1}]
Isaac Pak
0
const a = [{one:2},{two:2},{two:4}]
const b = a.filter(val => "two" in val).length;
if (b) {
   ...
}
pengguna1665355
sumber
3
Tolong dan beberapa deskripsi dan pastikan contoh yang Anda berikan berfungsi .. (filter tidak akan mengubah array asli tetapi mengkloningnya).
Moshe Simantov
-1

Pendekatan saya untuk memecahkan masalah ini adalah menggunakan ES6 dan membuat fungsi yang memeriksa kami. Manfaat dari fungsi ini adalah dapat digunakan kembali di seluruh proyek Anda untuk memeriksa berbagai objek yang diberikan keydan valueuntuk diperiksa.

BICARA CUKUP, LET'S SEE KODE

Himpunan

const ceos = [
  {
    name: "Jeff Bezos",
    company: "Amazon"
  }, 
  {
    name: "Mark Zuckerberg",
    company: "Facebook"
  }, 
  {
    name: "Tim Cook",
    company: "Apple"
  }
];

Fungsi

const arrayIncludesInObj = (arr, key, valueToCheck) => {
  let found = false;

  arr.some(value => {
    if (value[key] === valueToCheck) {
      found = true;
      return true; // this will break the loop once found
    }
  });

  return found;
}

Panggilan / Penggunaan

const found = arrayIncludesInObj(ceos, "name", "Tim Cook"); // true

const found = arrayIncludesInObj(ceos, "name", "Tim Bezos"); // false
rotimi-terbaik
sumber
-4

Saya lebih suka pergi dengan regex.

Jika kode Anda adalah sebagai berikut,

vendors = [
    {
      Name: 'Magenic',
      ID: 'ABC'
     },
    {
      Name: 'Microsoft',
      ID: 'DEF'
    }
];

saya ingin merekomendasikan

/"Name":"Magenic"/.test(JSON.stringify(vendors))
sangwook kim
sumber
24
Beberapa orang, ketika dihadapkan dengan masalah, berpikir "Saya tahu, saya akan menggunakan ekspresi reguler." Sekarang mereka memiliki dua masalah.
Craicerjack
Simpan ini di bawah, hanya karena Anda dapat melakukan sesuatu, tidak berarti Anda harus melakukannya.
Liam