Metode indexOf dalam array objek?

514

Apa metode terbaik untuk mendapatkan indeks array yang berisi objek?

Bayangkan skenario ini:

var hello = {
    hello: 'world',
    foo: 'bar'
};
var qaz = {
    hello: 'stevie',
    foo: 'baz'
}

var myArray = [];
myArray.push(hello,qaz);

Sekarang saya ingin memiliki indexOfobjek helloproperti yang 'stevie'mana, dalam contoh ini, akan 1.

Saya cukup pemula dengan JavaScript dan saya tidak tahu apakah ada metode sederhana atau apakah saya harus membangun fungsi saya sendiri untuk melakukan itu.

Antonio Laguna
sumber
1
Apakah Anda ingin menggabungkan dua objek hellodan qaz?
Armin
Tidak, tidak. Saya ingin memiliki daftar objek dalam array.
Antonio Laguna
Ah baiklah! Anda ingin mengetahui posisi seluruh objek dalam array, yang memiliki properti yang ditentukan.
Armin
10
Saya menemukan fungsi yang sangat sederhana untuk menyelesaikan masalah ini dengan jawaban SO ini: var elementPos = array.map(function(x) {return x.id; }).indexOf(idYourAreLookingFor); var objectFound = array[elementPos]; [tautan] ( stackoverflow.com/a/16100446/1937255 )
Rick
ES6 Array.indexOf lebih baik daripada jawaban yang diterima (jika ES6 bekerja untuk Anda) - lihat contoh lengkap di bawah ini
yar1

Jawaban:

1045

Saya pikir Anda bisa menyelesaikannya dalam satu baris menggunakan fungsi peta :

pos = myArray.map(function(e) { return e.hello; }).indexOf('stevie');
Pablo Francisco Pérez Hidalgo
sumber
58
Jujur ini harus menjadi jawaban yang diterima. Sebagian besar browser saat ini mendukungArray.prototype.map()
AlbertEngelB
10
Ini tidak didukung oleh IE8 tetapi, jika itu bukan masalah, ini adalah solusi terbaik.
Antonio Laguna
57
Um ... bukankah perlu dicatat bahwa Array.prototype.map () membuat array baru yang berisi item yang dipetakan? Jadi, jika Anda memiliki array dengan 1000 elemen, Anda telah membuat array lain dengan 1000 elemen terlebih dahulu, lalu mencarinya? Akan bermanfaat bagi saya berpikir untuk melihat kinerja metode ini vs sederhana untuk loop. Terutama ketika Anda menjalankan platform seluler dengan sumber daya terbatas.
Doug
7
@Doug Meskipun poin Anda tentang kinerja memang benar, siapa yang waras akan mengganti satu baris kode dengan tujuh untuk aplikasi yang hampir secara definisi IO / Jaringan terikat sampai mereka diprofilkan untuk kemacetan?
Jared Smith
6
Secara teknis file js yang
diperkecil
371

Array.prototype.findIndex didukung di semua browser selain IE (non-edge). Tapi polyfill yang disediakan bagus.

var indexOfStevie = myArray.findIndex(i => i.hello === "stevie");

Solusi dengan peta tidak apa-apa. Tapi Anda mengulangi seluruh array setiap pencarian. Itu hanya kasus terburuk untuk findIndex yang berhenti iterasi setelah kecocokan ditemukan.


Sebenarnya tidak ada cara ringkas (ketika dev harus khawatir tentang IE8) , tapi inilah solusi umum:

var searchTerm = "stevie",
    index = -1;
for(var i = 0, len = myArray.length; i < len; i++) {
    if (myArray[i].hello === searchTerm) {
        index = i;
        break;
    }
}

atau sebagai fungsi:

function arrayObjectIndexOf(myArray, searchTerm, property) {
    for(var i = 0, len = myArray.length; i < len; i++) {
        if (myArray[i][property] === searchTerm) return i;
    }
    return -1;
}
arrayObjectIndexOf(arr, "stevie", "hello"); // 1

Hanya beberapa catatan:

  1. Jangan gunakan untuk ... dalam loop pada array
  2. Pastikan untuk keluar dari loop atau kembali dari fungsi setelah Anda menemukan "jarum" Anda
  3. Hati-hati dengan persamaan objek

Sebagai contoh,

var a = {obj: 0};
var b = [a];
b.indexOf({obj: 0}); // -1 not found
Joe
sumber
fungsi memiliki perbandingan searchterm yang salah karena seharusnya searchTerm :)
Antonio Laguna
ada beberapa kejadian
Joe
3
@SteveBennett ini adalah versi yang dioptimalkan kinerja; panjang array harus ditentukan hanya sekali (ketika variabel untuk for-loop diinisialisasi). Dalam kasus Anda, panjangnya diperiksa setiap iterasi lagi. Lihat juga stackoverflow.com/questions/5349425/... dan stackoverflow.com/questions/8452317/... Namun, jika kinerjanya tidak tinggi, itu tidak masalah.
loother
1
Jawaban yang bagus, tetapi saya melakukan pembandingan kinerja (lihat jsperf.com/find-index-of-object-in-array-by-contents ), dan menemukan bahwa jawaban berbasis fungsi yang disebutkan di sini tampaknya merupakan jawaban yang paling berkinerja kedua. Satu-satunya hal yang lebih performant pada akhirnya adalah memasukkannya ke dalam prototipe, bukan hanya fungsi, seperti yang disebutkan dalam jawaban saya .
Uniphonic
123

Di ES2015, ini cukup mudah:

myArray.map(x => x.hello).indexOf('stevie')

atau, mungkin dengan kinerja yang lebih baik untuk array yang lebih besar:

myArray.findIndex(x => x.hello === 'stevie')
Steve Bennett
sumber
2
Pendekatan yang baik untuk menggunakan ES6
kag
Saya terkejut bahwa tidak satu pun dari metode ini adalah sebagai pemain seperti prototipe untuk loop, seperti yang disebutkan dalam jawaban saya. Meskipun dukungan browser metode findIndex agak buruk, sepertinya itu akan melakukan hal yang sama, tetapi masih berakhir kurang performan? Lihat tautan dalam jawaban saya untuk tolok ukur.
Uniphonic
Baik untuk diketahui, jika kinerja penting untuk tugas yang dihadapi. Sangat jarang, dalam pengalaman saya, tapi ymmv.
Steve Bennett
24
var idx = myArray.reduce( function( cur, val, index ){

    if( val.hello === "stevie" && cur === -1 ) {
        return index;
    }
    return cur;

}, -1 );
Esailija
sumber
17

Saya suka jawaban Pablo, tetapi peta Array # indexOf dan Array # tidak berfungsi di semua browser. Garis bawah akan menggunakan kode asli jika tersedia, tetapi memiliki fallback juga. Plus itu memiliki metode pemetik untuk melakukan apa yang dilakukan metode peta anonim Pablo.

var idx = _.chain(myArray).pluck("hello").indexOf("Stevie").value();
tandrewnichols
sumber
1
Array.prototype.map () didukung untuk IE9 + dan Anda dapat menggunakan Polyfill untuk IE8, 7, 6: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Johann Echavarria
1
Anda bisa menggunakan polyfill. . . atau Anda bisa menggunakan underscore atau lodash, yang pada dasarnya adalah polyfill yang memiliki banyak barang lain . Apa keberatan dengan garis bawah? Ukuran?
tandrewnichols
Saya sangat suka Underscore, jawaban Anda juga cerdas, tetapi jawaban IMHO Pablo adalah yang terbersih.
Johann Echavarria
Wow saya tidak pernah terpikir untuk menggunakan chaining seperti itu. Saya sangat suka bagaimana membuat pencarian lancar.
Dylan Pierce
chainberlebihan di sini. _.pluck(myArray, 'hello').indexOf('stevie')
Steve Bennett
14

Atau prototipe:

Array.prototype.indexOfObject = function arrayObjectIndexOf(property, value) {
    for (var i = 0, len = this.length; i < len; i++) {
        if (this[i][property] === value) return i;
    }
    return -1;
}

myArr.indexOfObject("name", "stevie");
Nathan Zaetta
sumber
9
Sangat mudah! Meskipun saya akan memilih prototype.indexOfObject agar tidak mengganggu metode Array.indexOf exisitng. Array.prototype.indexOfObject = function(property, value) { for (var i = 0, len = this.length; i < len; i++) { if (this[i][property] === value) return i; } return -1; };
Adam
1
Saya akan membungkusnya dalam penutupan mengeksekusi diri dengan yang lama disimpan sebelumnya, dengan baris pertama dari fungsi penggantian menjadi sesuatu di sepanjang baris if (typeof property === 'string' || typeof property === 'number' || typeof property === 'boolean') return oldIndexOf(property, value);. Ini karena ini adalah beberapa tipe yang tidak berubah. Saya juga akan menampilkan argumen ketiga untuk mengaktifkan fallback ke metode asli jika diperlukan.
Isiah Meadows
8

Singkat

myArray.indexOf('stevie','hello')

Gunakan Kasus:

  /*****NORMAL****/  
[2,4,5].indexOf(4) ;//OUTPUT 1
 /****COMPLEX*****/
 [{slm:2},{slm:4},{slm:5}].indexOf(4,'slm');//OUTPUT 1
 //OR
 [{slm:2},{slm:4},{slm:5}].indexOf(4,function(e,i){
   return e.slm;
});//OUTPUT 1
/***MORE Complex**/
[{slm:{salat:2}},{slm:{salat:4}},{slm:{salat:5}}].indexOf(4,function(e,i){
   return e.slm.salat;
});//OUTPUT 1

API:

    Array.prototype.indexOfOld=Array.prototype.indexOf

    Array.prototype.indexOf=function(e,fn){
      if(!fn){return this.indexOfOld(e)}
      else{ 
       if(typeof fn ==='string'){var att=fn;fn=function(e){return e[att];}}
        return this.map(fn).indexOfOld(e);
      }
    };
Abdennour TOUMI
sumber
6

Saya melakukan beberapa pengujian kinerja berbagai jawaban di sini, yang dapat dijalankan sendiri oleh siapa saja:

https://jsperf.com/find-index-of-object-in-array-by-contents

Berdasarkan tes awal saya di Chrome, metode berikut (menggunakan for loop yang diatur di dalam prototipe) adalah yang tercepat:

Array.prototype.indexOfObject = function (property, value) {
    for (var i = 0, len = this.length; i < len; i++) {
        if (this[i][property] === value) return i;
    }
    return -1;
}

myArray.indexOfObject("hello", "stevie");

Kode ini adalah versi yang sedikit dimodifikasi dari jawaban Nathan Zaetta.

Dalam tolok ukur kinerja saya mencobanya dengan target berada di tengah (indeks 500) dan sangat akhir (indeks 999) dari 1000 objek array, dan bahkan jika saya meletakkan target sebagai item terakhir dalam array (artinya bahwa ia harus melalui setiap item dalam array sebelum ditemukan) itu masih berakhir tercepat.

Solusi ini juga memiliki manfaat menjadi salah satu yang paling singkat untuk eksekusi berulang kali, karena hanya baris terakhir yang perlu diulang:

myArray.indexOfObject("hello", "stevie");
Uniphonic
sumber
2
Saya baru saja akan mengirim jawaban untuk pertanyaan ini menggunakan biola dengan tes saya sendiri, tetapi berkat jawaban Anda, saya tidak perlu lagi. Saya hanya ingin mengonfirmasi tes Anda - saya mendapatkan hasil yang sama, tetapi menggunakan satu whilelingkaran, bukan forsatu, dan performance.now(). Saya berharap jawaban ini lebih terangkat dan saya melihatnya lebih awal, itu akan menghemat waktu saya ...
Yin Cognyto
5

Saya membandingkan beberapa metode dan menerima hasil dengan cara tercepat untuk menyelesaikan masalah ini. Itu sebuah forlingkaran. Ini 5+ kali lebih cepat daripada metode lainnya.

Inilah halaman tesnya: https://jsbench.me/9hjewv6a98

John Klimov
sumber
Tidak ada satu for-oflingkaran pun?
Douglas Gaskell
5

Sementara, sebagian besar jawaban lain di sini valid. Terkadang, yang terbaik adalah membuat fungsi sederhana pendek di dekat tempat Anda akan menggunakannya.

// indexOf wrapper for the list of objects
function indexOfbyKey(obj_list, key, value) {
    for (index in obj_list) {
        if (obj_list[index][key] === value) return index;
    }
    return -1;
}
// Find the string in the list (default -1)
var test1 = indexOfbyKey(object_list, 'name', 'Stevie');
var test2 = indexOfbyKey(object_list, 'last_name', 'some other name');

Itu tergantung pada apa yang penting bagi Anda. Mungkin menyimpan baris kode dan sangat pintar untuk menggunakan satu-liner, atau untuk menempatkan solusi generik di suatu tempat yang mencakup berbagai kasus tepi. Tapi kadang-kadang lebih baik mengatakan: "di sini aku melakukannya seperti ini" daripada meninggalkan pengembang masa depan untuk memiliki pekerjaan rekayasa balik ekstra. Terutama jika Anda menganggap diri Anda "seorang pemula" seperti dalam pertanyaan Anda.

SpiRail
sumber
4
array.filter(function(item, indx, arr){ return(item.hello === 'stevie'); })[0];

Pikirkan itu [0].

Sangat tepat untuk digunakan reducesebagai Antonio Lagunajawaban.

Permintaan maaf untuk singkatnya ...

Cody
sumber
4

Jika objek Anda adalah objek yang sama dengan yang Anda gunakan dalam array, Anda harus bisa mendapatkan indeks Obyek dengan cara yang sama seperti jika Anda menggunakan string.

var hello = {
    hello: 'world',
    foo: 'bar'
};
var qaz = {
    hello: 'stevie',
    foo: 'baz'
}

var qazCLONE = { // new object instance and same structure
    hello: 'stevie',
    foo: 'baz'
}

var myArray = [hello,qaz];

myArray.indexOf(qaz) // should return 1
myArray.indexOf(qazCLONE) // should return -1
Caio Koiti
sumber
Ini adalah jawaban yang saya cari karena tidak jelas bagi saya apakah IndexOf cocok dengan nilai atau apa. Sekarang saya tahu saya bisa menggunakan IndexOf untuk menemukan objek saya, dan tidak khawatir jika ada objek lain dengan properti yang sama.
MDave
3

sederhana:

myArray.indexOf(myArray.filter(function(item) {
    return item.hello == "stevie"
})[0])
burung bangkai griffon
sumber
3

Jika Anda hanya tertarik untuk menemukan posisi tersebut, lihat jawaban @ Pablo .

pos = myArray.map(function(e) { return e.hello; }).indexOf('stevie');

Namun, jika Anda ingin menemukan elemen (yaitu jika Anda berpikir untuk melakukan sesuatu seperti ini myArray[pos]), ada cara satu-line yang lebih efisien untuk melakukannya, menggunakan filter.

element = myArray.filter((e) => e.hello === 'stevie')[0];

Lihat hasil kinerja (~ + 42% ops / dtk): http://jsbench.github.io/#7fa01f89a5dc5cc3bee79abfde80cdb3

zurfyx
sumber
2

Lihat contoh ini: http://jsfiddle.net/89C54/

for (i = 0; i < myArray.length; i++) {
    if (myArray[i].hello === 'stevie') {
        alert('position: ' + i);
        return;
    }
}

Mulai menghitung dengan nol.

Armin
sumber
2

Saya telah membuat fungsi generik untuk memeriksa di bawah ini adalah kode & berfungsi untuk objek apa pun

function indexOfExt(list, item) {
    var len = list.length;

    for (var i = 0; i < len; i++) {
        var keys = Object.keys(list[i]);
        var flg = true;
        for (var j = 0; j < keys.length; j++) {
            var value = list[i][keys[j]];
            if (item[keys[j]] !== value) {
                flg = false;
            }
        }
        if (flg == true) {
            return i;
        }
    }
    return -1;
}

var items = [{ "hello": 'world', "foo": 'bar' }];
var selectedItem = { "hello": 'world', "foo": 'bar' };
alert(items.indexOf(selectedItem));
alert(indexOfExt(items, selectedItem));

Lansiran pertama akan mengembalikan -1 (berarti kecocokan tidak ditemukan) & lansiran kedua akan mengembalikan 0 (berarti kecocokan ditemukan).

Shiljo Paulson
sumber
2

Gunakan _.findIndexdari perpustakaan underscore.js

Inilah contohnya _.findIndex([{a:1},{a: 2,c:10},{a: 3}], {a:2,c:10}) //1

niren
sumber
Jika menyarankan metode dari perpustakaan tambahan Anda harus menyebutkan dari mana mereka berasal.
Craicerjack
@Steve Bennett penggunaan yang bagus. Sekarang perpustakaannya berada di lodash
zabusa
2

Menggunakan findIndexmetode ES6 , tanpa lodash atau perpustakaan lain, Anda dapat menulis:

function deepIndexOf(arr, obj) {
  return arr.findIndex(function (cur) {
    return Object.keys(obj).every(function (key) {
      return obj[key] === cur[key];
    });
  });
}

Ini akan membandingkan properti langsung objek, tetapi tidak berulang ke properti.

Jika implementasi Anda belum menyediakan findIndex(kebanyakan tidak), Anda dapat menambahkan polyfill ringan yang mendukung pencarian ini:

function deepIndexOf(arr, obj) {
  function findIndex = Array.prototype.findIndex || function (pred) {
    for (let i = 0; i < this.length; ++i) {
      if (pred.call(this, this[i], i)) {
        return i;
      }
    }

    return -1;
  }

  return findIndex.call(arr, function (cur) {
    return Object.keys(obj).every(function (key) {
      return obj[key] === cur[key];
    });
  });
}

(dari jawaban saya pada penipuan ini )

ssube
sumber
2

Anda dapat menggunakan fungsi asli dan nyaman Array.prototype.findIndex()pada dasarnya:

Metode findIndex () mengembalikan indeks dalam array, jika elemen dalam array memenuhi fungsi pengujian yang disediakan. Kalau tidak -1 dikembalikan.

Hanya catatan itu tidak didukung di Internet Explorer, Opera dan Safari, tetapi Anda dapat menggunakan Polyfill yang disediakan di tautan di bawah ini.

Informasi lebih lanjut:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex

var hello = {
  hello: 'world',
  foo: 'bar'
};
var qaz = {
  hello: 'stevie',
  foo: 'baz'
}

var myArray = [];
myArray.push(hello, qaz);

var index = myArray.findIndex(function(element, index, array) {
  if (element.hello === 'stevie') {
    return true;
  }
});
alert('stevie is at index: ' + index);

GibboK
sumber
2

Lebih jauh dari jawaban @Monika Garg , Anda dapat menggunakan findIndex()(Ada polyfill untuk peramban yang tidak didukung).

Saya melihat bahwa orang menolak jawaban ini, dan saya berharap mereka melakukan ini karena sintaks yang salah, karena menurut pendapat saya, ini adalah cara yang paling elegan.

Metode findIndex () mengembalikan indeks dalam array, jika elemen dalam array memenuhi fungsi pengujian yang disediakan. Kalau tidak -1 dikembalikan.

Sebagai contoh:

var hello = {
  hello: 'world',
  foo: 'bar'
};
var qaz = {
  hello: 'stevie',
  foo: 'baz'
}

var myArray = [];
myArray.push(hello,qaz);

var index = myArray.findIndex(function(element) {
  return element.hello == 'stevie';
});

alert(index);

Mosh Feu
sumber
Metode ini tampak elegan, tetapi tidak ada dukungan IE menurut MDN? developer.mozilla.org/en/docs/Web/JavaScript/Reference/…
Jaakko Karhu
Coba gunakan polyfill (tautan dalam jawaban).
Mosh Feu
1

Ini adalah cara untuk menemukan indeks objek dalam array

    var myArray = [{  hello: 'world',
        foo: 'bar'
    },{
        hello: 'stevie',
        foo: 'baz'
    }];



    for (i = 0; i < myArray.length; i++) {
        if (myArray[i].hello === 'stevie') {
            alert('position: ' + i);
            return;
        }
    }
Asad Fida
sumber
0

Ini berfungsi tanpa kode khusus

var arr, a, found;
arr = [{x: 1, y: 2}];
a = {x: 1, y: 2};
found = JSON.stringify(arr).indexOf(JSON.stringify(a)) > - 1;
// found === true

Catatan: ini tidak memberikan indeks yang sebenarnya, ini hanya memberi tahu jika objek Anda ada di struktur data saat ini

Xeltor
sumber
1
Ini tidak valid karena ini tidak memungkinkan untuk mendapatkan indeks apa pun
Antonio Laguna
0

Anda cukup menggunakan

const someId = 2;
const array = [{id:1}, {id:2}, {id:3}];
const index = array.reduce((i, item, index) => item.id === someId ? index : i, -1);
alert('someId ' + someId + ' is at index ' + index);

Tidak ada garis bawah, tidak untuk, hanya pengurangan.

7ynk3r
sumber
0
var hello = {hello: "world",  foo: "bar"};
var qaz = {hello: "stevie", foo: "baz"};
var myArray = [];
myArray.push(hello,qaz);

function indexOfObject( arr, key, value   ) {
    var j = -1;
    var result = arr.some(function(obj, i) { 
        j++;
        return obj[key] == value;
    })

    if (!result) {
        return -1;
    } else {
        return j;
    };
}

alert(indexOfObject(myArray,"hello","world"));
pengguna3235365
sumber
Gunakan Array beberapa metode.
user3235365
-1

Anda dapat membuat prototipe Anda sendiri untuk melakukan ini:

sesuatu seperti:

Array.prototype.indexOfObject = function (object) {
    for (var i = 0; i < this.length; i++) {
        if (JSON.stringify(this[i]) === JSON.stringify(object))
            return i;
    }
}
Janx dari Venezuela
sumber
2
Praktik buruk, melanggar enkapsulasi: developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/…
HMR
Ini juga akan merusak objek yang didefinisikan secara rekursif.
Joseph Coco
-2

Saya lebih suka menggunakan findIndex()metode:

 var index = myArray.findIndex('hello','stevie');

index akan memberi Anda nomor indeks.

Monika Garg
sumber
1
Jawaban, Ejaan dan Indentasi Kode dan :) salah?
Sachin Verma
1
findIndex tidak dalam implementasi standar javascript. Ada proposal (ecma 6) yang akan datang untuk metode seperti itu, tetapi tanda tangannya tidak seperti itu. Tolong, jelaskan apa yang Anda maksud (mungkin nama metode), berikan deklarasi metode findIndex atau beri nama perpustakaan yang Anda gunakan.
Sebastien F.