Dapatkan indeks objek di dalam array, cocok dengan suatu kondisi

322

Saya memiliki array seperti ini:

[{prop1:"abc",prop2:"qwe"},{prop1:"bnmb",prop2:"yutu"},{prop1:"zxvz",prop2:"qwrq"},...]

Bagaimana saya bisa mendapatkan indeks objek yang cocok dengan suatu kondisi, tanpa mengulangi seluruh array?

Misalnya, mengingat prop2=="yutu", saya ingin mendapatkan indeks 1.

Saya melihat .indexOf()tetapi berpikir itu digunakan untuk array sederhana seperti ["a1","a2",...]. Saya juga memeriksa $.grep()tetapi ini mengembalikan objek, bukan indeks.

amp
sumber

Jawaban:

733

Mulai 2016, Anda seharusnya menggunakan Array.findIndex(standar ES2015 / ES6) untuk ini:

a = [
  {prop1:"abc",prop2:"qwe"},
  {prop1:"bnmb",prop2:"yutu"},
  {prop1:"zxvz",prop2:"qwrq"}];
    
index = a.findIndex(x => x.prop2 ==="yutu");

console.log(index);

Ini didukung di Google Chrome, Firefox dan Edge. Untuk Internet Explorer, ada polyfill pada halaman tertaut.

Catatan kinerja

Panggilan fungsi mahal, oleh karena itu dengan array yang sangat besar, loop sederhana akan berkinerja lebih baik daripada findIndex:

let test = [];

for (let i = 0; i < 1e6; i++)
    test.push({prop: i});


let search = test.length - 1;
let count = 100;

console.time('findIndex/predefined function');
    let fn = obj => obj.prop === search;

    for (let i = 0; i < count; i++)
        test.findIndex(fn);
console.timeEnd('findIndex/predefined function');


console.time('findIndex/dynamic function');
    for (let i = 0; i < count; i++)
        test.findIndex(obj => obj.prop === search);
console.timeEnd('findIndex/dynamic function');


console.time('loop');
    for (let i = 0; i < count; i++) {
        for (let index = 0; index < test.length; index++) {
            if (test[index].prop === search) {
                break;
            }
        }
    }
console.timeEnd('loop');

Seperti kebanyakan optimisasi, ini harus diterapkan dengan hati-hati dan hanya ketika benar-benar dibutuhkan.

georg
sumber
3
Saya tidak melihat perlunya array sementara di sini. Cukup gunakan fakta bahwa fungsi iterator menutup konteks dan menggunakan variabel. Juga, versi non-jQuery tidak berfungsi (misalkan ditemukan di indeks 0?). Kedua solusi melakukan lebih iterasi dari yang dibutuhkan, yang kurang dari ideal jika array besar (meskipun kemungkinan itu menjadi manusia begitu besar akan melihat yang rendah, kecuali pencarian yang terjadi a lot ).
TJ Crowder
@ thg435: Masih berpikir itu sedikit mesin Rube Goldberg di mana tuas sederhana akan melakukan trik. :-) Tapi hei, itu berhasil!
TJ Crowder
4
Bisakah Anda jelaskan cara x => x.prop2=="yutu"kerjanya dengan findIndex ()?
Abhay Pai
5
@AbhayPai: sama denganfunction(x) { return x.prop2=="yutu" }
georg
6
Saya suka saran untuk menggunakan polyfill. Namun kode yang ditulis masih gagal di IE11 bahkan dengan polyfill karena penggunaan fungsi panah / lambda. Ditulis ulang sebagai index = a.findIndex(function (x) { return x.prop2 == "yutu" })memperbaiki masalah sehingga dengan kode polyfill, findIndex bekerja di IE11
Rick Glos
26

Bagaimana saya bisa mendapatkan indeks objek yang cocok dengan kondisi (tanpa iterate sepanjang array)?

Anda tidak bisa, sesuatu harus diulang melalui array (setidaknya sekali).

Jika kondisinya banyak berubah, maka Anda harus mengulang dan melihat objek di dalamnya untuk melihat apakah mereka cocok dengan kondisinya. Namun, pada sistem dengan fitur ES5 (atau jika Anda menginstal shim), iterasi dapat dilakukan dengan cukup ringkas:

var index;
yourArray.some(function(entry, i) {
    if (entry.prop2 == "yutu") {
        index = i;
        return true;
    }
});

Itu menggunakan (ish) baru Array#some fungsi , yang loop melalui entri dalam array sampai fungsi yang memberikan mengembalikan nilai true. Fungsi yang saya berikan ini menyimpan indeks entri yang cocok, lalu kembali trueuntuk menghentikan iterasi.

Atau tentu saja, gunakan a for lingkaran. Berbagai opsi iterasi Anda tercakup dalam jawaban lain ini .

Tetapi jika Anda akan selalu menggunakan properti yang sama untuk pencarian ini, dan jika nilai properti unik, Anda dapat mengulangi sekali saja dan membuat objek untuk memetakannya:

var prop2map = {};
yourArray.forEach(function(entry) {
    prop2map[entry.prop2] = entry;
});

(Atau, sekali lagi, Anda bisa menggunakan forloop atau salah satunya opsi lain .)

Maka jika Anda perlu menemukan entri prop2 = "yutu", Anda dapat melakukan ini:

var entry = prop2map["yutu"];

Saya menyebutnya "lintas-pengindeksan" array. Secara alami, jika Anda menghapus atau menambah entri (atau mengubah prop2nilainya), Anda perlu memperbarui objek pemetaan Anda juga.

TJ Crowder
sumber
Terima kasih untuk penjelasannya! Solusi dengan jQuery ditunjuk oleh thg435melakukan apa yang saya inginkan ...
amp
21

Apa yang dikatakan TJ Crowder, semua akan memiliki semacam iterasi tersembunyi, dengan lodash ini menjadi:

var index = _.findIndex(array, {prop2: 'yutu'})
aliak
sumber
1
sementara Anda bisa melalui berbagai cara untuk mendapatkan indeks, temukan Index adalah solusi terbaik, bahkan diadopsi dalam ES6 ke dalam metode array asli
Kelly Milligan
13
var CarId = 23;

//x.VehicleId property to match in the object array
var carIndex = CarsList.map(function (x) { return x.VehicleId; }).indexOf(CarId);

Dan untuk nomor array dasar Anda juga dapat melakukan ini:

var numberList = [100,200,300,400,500];
var index = numberList.indexOf(200); // 1

Anda akan mendapatkan -1 jika tidak dapat menemukan nilai dalam array.

David Castro
sumber
11
var index;
yourArray.some(function (elem, i) {
    return elem.prop2 === 'yutu' ? (index = i, true) : false;
});

Iterate atas semua elemen array. Ini mengembalikan indeks dan benar atau salah jika kondisinya tidak cocok.

Penting adalah nilai pengembalian eksplisit true (atau nilai yang hasilnya boolean benar). Penugasan tunggal tidak memadai, karena kemungkinan indeks dengan 0 (Boolean (0) === false), yang tidak akan menghasilkan kesalahan tetapi menonaktifkan jeda iterasi.

Edit

Versi yang lebih pendek dari yang di atas:

yourArray.some(function (elem, i) {
    return elem.prop2 === 'yutu' && ~(index = i);
});
Nina Scholz
sumber
Apa yang dilakukan ~ karakter di cuplikan kedua Anda?
serkan
@serkan, itu adalah bitwise TIDAK| operator, itu adalah versi pendek untuk mendapatkan dari indeks (dengan -1) a truthy / falsy hasil, jika indeks ada.
Nina Scholz
terima kasih Nina, Tanpa ~ karakter, kode berfungsi seperti apa adanya, bukan?
serkan
@serkan, pertanyaan Anda tidak jelas, tetapi tanpa ~itu tidak berfungsi seperti itu.
Nina Scholz
1
oh, !!(index = 0)dan !!~(index = 0)memang perbedaan. Terima kasih!
serkan
4

Anda dapat menggunakan Array.prototype.some () dengan cara berikut (sebagaimana disebutkan dalam jawaban lain):

https://jsfiddle.net/h1d69exj/2/

function findIndexInData(data, property, value) {
    var result = -1;
    data.some(function (item, i) {
        if (item[property] === value) {
            result = i;
            return true;
        }
    });
    return result;
}
var data = [{prop1:"abc",prop2:"qwe"},{prop1:"bnmb",prop2:"yutu"},{prop1:"zxvz",prop2:"qwrq"}]



alert(findIndexInData(data, 'prop2', "yutu")); // shows index of 1
GibboK
sumber
4

Saya telah melihat banyak solusi di atas.

Di sini saya menggunakan fungsi peta untuk menemukan indeks teks pencarian di objek array.

Saya akan menjelaskan jawaban saya dengan menggunakan data siswa.

  • langkah 1 : buat objek array untuk siswa (opsional Anda dapat membuat objek array Anda sendiri).
    var students = [{name:"Rambabu",htno:"1245"},{name:"Divya",htno:"1246"},{name:"poojitha",htno:"1247"},{name:"magitha",htno:"1248"}];

  • langkah 2 : Buat variabel untuk mencari teks
    var studentNameToSearch = "Divya";

  • langkah 3 : Buat variabel untuk menyimpan indeks yang cocok (di sini kami menggunakan fungsi peta untuk beralih).
    var matchedIndex = students.map(function (obj) { return obj.name; }).indexOf(studentNameToSearch);

var students = [{name:"Rambabu",htno:"1245"},{name:"Divya",htno:"1246"},{name:"poojitha",htno:"1247"},{name:"magitha",htno:"1248"}];

var studentNameToSearch = "Divya";

var matchedIndex = students.map(function (obj) { return obj.name; }).indexOf(studentNameToSearch);

console.log(matchedIndex);

alert("Your search name index in array is:"+matchedIndex)

Rambabu Bommisetti
sumber
3
function findIndexByKeyValue(_array, key, value) {
    for (var i = 0; i < _array.length; i++) { 
        if (_array[i][key] == value) {
            return i;
        }
    }
    return -1;
}
var a = [
    {prop1:"abc",prop2:"qwe"},
    {prop1:"bnmb",prop2:"yutu"},
    {prop1:"zxvz",prop2:"qwrq"}];
var index = findIndexByKeyValue(a, 'prop2', 'yutu');
console.log(index);
pranabesh chand
sumber
1

Mengapa Anda tidak ingin mengulanginya dengan tepat? Array.prototype.forEach baru sangat bagus untuk tujuan ini!

Anda dapat menggunakan Pohon Pencarian Biner untuk menemukan melalui panggilan metode tunggal jika Anda mau. Ini adalah implementasi rapi dari pohon Pencarian BTree dan Red black di JS - https://github.com/vadimg/js_bintrees - tapi saya tidak yakin apakah Anda dapat menemukan indeks pada saat yang sama.

Rishabh
sumber
1

Satu langkah menggunakan Array.reduce () - tanpa jQuery

var items = [{id: 331}, {id: 220}, {id: 872}];

var searchIndexForId = 220;
var index = items.reduce(function(searchIndex, item, index){
  if(item.id === searchIndexForId) { 
    console.log('found!');
    searchIndex = index;
  }
  return searchIndex;
}, null);

akan kembali nulljika indeks tidak ditemukan.

SagiSergeNadir
sumber
0
var list =  [
                {prop1:"abc",prop2:"qwe"},
                {prop1:"bnmb",prop2:"yutu"},
                {prop1:"zxvz",prop2:"qwrq"}
            ];

var findProp = p => {
    var index = -1;
    $.each(list, (i, o) => {
        if(o.prop2 == p) {
            index = i;
            return false; // break
        }
    });
    return index; // -1 == not found, else == index
}
Ruben Morales Felix
sumber
0

Georg telah menyebutkan ES6 memiliki Array.findIndex untuk ini. Dan beberapa jawaban lain adalah solusi untuk ES5 menggunakan metode Array.some.

Satu lagi pendekatan elegan bisa dilakukan

var index;
for(index = yourArray.length; index-- > 0 && yourArray[index].prop2 !== "yutu";);

Pada saat yang sama saya ingin menekankan, Array.some dapat diimplementasikan dengan teknik pencarian biner atau efisien lainnya. Jadi, ini mungkin berperforma lebih baik untuk loop di beberapa browser.

Sanjoy
sumber
0

Coba kode ini

var x = [{prop1:"abc",prop2:"qwe"},{prop1:"bnmb",prop2:"yutu"},{prop1:"zxvz",prop2:"qwrq"}]
let index = x.findIndex(x => x.prop1 === 'zxvz')
Trilok Singh
sumber