Bagaimana cara mendapatkan indeks objek berdasarkan propertinya di JavaScript?

241

Sebagai contoh, saya punya:

var Data = [
  { id_list: 1, name: 'Nick', token: '312312' },
  { id_list: 2, name: 'John', token: '123123' },
]

Lalu, saya ingin mengurutkan / membalikkan objek ini dengan name, misalnya. Dan kemudian saya ingin mendapatkan sesuatu seperti ini:

var Data = [
  { id_list: 2, name: 'John', token: '123123' },
  { id_list: 1, name: 'Nick', token: '312312' },
]

Dan sekarang saya ingin tahu indeks objek dengan properti name='John'untuk mendapatkan nilai token properti.

Bagaimana saya mengatasi masalah?

rsboarder
sumber
Mengapa Anda ingin mengurutkan daftar terlebih dahulu sebelum mencari properti?
JJJ
Objek JavaScript adalah {Key:Value}, saya memperbaikinya untuk Anda.
Rocket Hazmat
kemungkinan duplikat array Cari JSON untuk atribut yang cocok
outis
Jika Anda memindai melalui jawaban, sepertinya ada beberapa Dataobjek asli . Ini hanyalah nama variabel dengan huruf kapital, yang bertentangan dengan konvensi. Jika ada orang lain yang terganggu dengan ini, saya akan mengedit pertanyaan dan jawaban untuk memperbaiki penamaan ini.
Roy Prins
Pertanyaan terkait: stackoverflow.com/questions/10557486/…
Anton Tarasenko

Jawaban:

170

Seperti jawaban lain yang disarankan, perulangan melalui array mungkin adalah cara terbaik. Tapi saya akan memasukkannya ke dalam fungsinya sendiri, dan membuatnya sedikit lebih abstrak:

function findWithAttr(array, attr, value) {
    for(var i = 0; i < array.length; i += 1) {
        if(array[i][attr] === value) {
            return i;
        }
    }
    return -1;
}

var Data = [
    {id_list: 2, name: 'John', token: '123123'},
    {id_list: 1, name: 'Nick', token: '312312'}
];

Dengan ini, Anda tidak hanya dapat menemukan yang berisi 'John' tetapi Anda dapat menemukan yang berisi token '312312':

findWithAttr(Data, 'name', 'John'); // returns 0
findWithAttr(Data, 'token', '312312'); // returns 1
findWithAttr(Data, 'id_list', '10'); // returns -1

EDIT: Fungsi yang diperbarui untuk mengembalikan -1 ketika tidak ditemukan sehingga mengikuti konstruk yang sama dengan Array.prototype.indexOf ()

Chris Pickett
sumber
1
Jawaban yang ditambahkan memperluas ini untuk mencakup pencarian yang lebih dalam dari satu level atribut. Terima kasih untuk ini Chris - sangat membantu: D
Ed Shee
3
Bagi mereka yang akan mengalami masalah dengan solusi ini, ingat bahwa tanda === sama tidak hanya akan memeriksa nilai tetapi juga tipe data. jadi membandingkan tanggal, angka, dan nilai kosong dapat menghasilkan false jika nilai sebenarnya adalah string. Anda dapat menggunakan == tanda sama dengan jika tipe data tidak penting bagi Anda.
David Addoteye
JANGAN LAKUKAN INI. Pelajari cara menggunakan fungsi tingkat tinggi ini adalah cara lama dalam melakukan sesuatu.
Dipimpin
327

Karena bagian pengurutan sudah dijawab. Saya hanya akan mengusulkan cara elegan lain untuk mendapatkan indexOf dari properti di array Anda

Contoh Anda adalah:

var Data = [
    {id_list:1, name:'Nick',token:'312312'},
    {id_list:2,name:'John',token:'123123'}
]

Anda dapat melakukan:

var index = Data.map(function(e) { return e.name; }).indexOf('Nick');

Array.prototype.maptidak tersedia di IE7 atau IE8. Kompatibilitas ES5

Dan ini dia dengan sintaks ES6 dan panah, yang bahkan lebih sederhana:

const index = Data.map(e => e.name).indexOf('Nick');
Attanasio Jerman
sumber
4
Saya harus mengulang seluruh array apa pun yang terjadi. Metode pertama tidak perlu.
Attanasio Jerman,
1
Sederhana, tetapi memperhitungkan kinerja ketika menggunakan dataset besar
gavioto
1
Jawaban yang sangat bagus membantu saya dengan masalah ini!
NiallMitch14
1
Solusi ini sangat bagus. Semoga Anda berumur seribu tahun, tuan.
deepelement
3
Melakukan peta dan kemudian indexOf dalam versi ES6 berarti mereka akan mengulang array dua kali. Alih-alih, Anda harus menggunakan metode findIndex yang ditunjukkan dalam jawaban saya
silverlight513
209

Jika Anda baik-baik saja dengan menggunakan ES6. Array sekarang memiliki fungsi findIndex . Yang berarti Anda dapat melakukan sesuatu seperti ini:

const index = Data.findIndex(item => item.name === 'John');
silverlight513
sumber
6
solusi langsung ke bawah dan elegan, saya akan membuat yang kecil tidak menemukan findIndex serakah - dalam kasus saya yang sempurna - tetapi pengguna menyadari bahwa jika Anda memiliki objek dengan nilai duplikat (yaitu dua objek dengan name: John) ini hanya akan mengembalikan pertandingan pertama
GrayedFox
Hebat !! Terima kasih.
moreirapontocom
@GrayedFox bukankah maksud Anda TIDAK serakah? Serakah berarti lebih banyak hasil dan menemukanIndex hanya mengembalikan pertandingan pertama.
Jos
1
Maaf @ Jo tapi saya pikir Anda tidak begitu mengerti apa yang dilakukan oleh algoritma pencarian serakah . Algoritma serakah hanya mempertimbangkan informasi yang dimilikinya, yang secara komputasi efisien untuk, katakanlah, mencari item dalam daftar ketika Anda hanya membutuhkan satu hasil. Metode findIndex sangat serakah karena hanya mengembalikan kecocokan pertama. Jika tidak serakah itu akan terus mencari. Anda memikirkan istilah "rakus" seperti yang digunakan dalam bahasa Inggris sehari-hari, tetapi dalam konteks pemrograman (yaitu SO), itu kebalikan dari apa yang Anda pikirkan;)
GrayedFox
Terima kasih telah menjelaskan @GrayedFox. Referensi saya untuk serakah sebenarnya dari pemrograman juga tetapi terkait dengan ekspresi reguler di mana serakah mengambil lebih banyak karakter daripada non-serakah! :-)
Jos
28
var index = Data.findIndex(item => item.name == "John")

Yang merupakan versi sederhana dari:

var index = Data.findIndex(function(item){ return item.name == "John"})

Dari mozilla.org:

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

Edank
sumber
2
Gunakan "===" untuk perbandingan string. Satu-satunya hal yang hilang dalam jawaban ini.
Bruno Tavares
@BrunoTavares, skenario mana yang menurut Anda akan berbeda dalam kasus ini?
edank
1
@edank. Jika OP memeriksa tokenbidang, bukan namebidang, mungkin ada masalah, seperti yang Data[0].token == 312312dievaluasi true, tetapi Data[0].token === 321321dievaluasi false.
kem
@edank perhatikan jawaban ini stackoverflow.com/questions/359494/...
Bruno Tavares
23

Jika Anda mengalami masalah dengan IE, Anda bisa menggunakan fungsi map () yang didukung mulai 9.0 dan seterusnya:

var index = Data.map(item => item.name).indexOf("Nick");
Alain T.
sumber
1
Jawaban di bawah ini memberikan informasi lebih lanjut dan diposting pertama kali.
Alexander
Ini jelas merupakan solusi terbaik untuk ini.
Bebolicious
4

Satu-satunya cara yang diketahui bagi saya adalah dengan mengulang-ulang semua array:

var index=-1;
for(var i=0;i<Data.length;i++)
  if(Data[i].name==="John"){index=i;break;}

atau case sensitive:

var index=-1;
for(var i=0;i<Data.length;i++)
  if(Data[i].name.toLowerCase()==="john"){index=i;break;}

Pada indeks hasil variabel berisi indeks objek atau -1 jika tidak ditemukan.

Andrew D.
sumber
2

cara prototipe

(function(){
  if (!Array.prototype.indexOfPropertyValue){
    Array.prototype.indexOfPropertyValue = function(prop,value){
      for (var index = 0; index < this.length; index++){
        if (this[index][prop]){
          if (this[index][prop] == value){
            return index;
          }
        }
      }
      return -1;
    }
  }
 })();
 // usage:
 var Data = [
 {id_list:1, name:'Nick',token:'312312'},{id_list:2,name:'John',token:'123123'}];
 Data.indexOfPropertyValue('name','John'); // returns 1 (index of array);
 Data.indexOfPropertyValue('name','Invalid name') // returns -1 (no result);
 var indexOfArray = Data.indexOfPropertyValue('name','John');
 Data[indexOfArray] // returns desired object.
Patrik Wallin
sumber
Saya harus mengubah ini sedikit agar sesuai dengan situasi saya - saya mencari indeks properti dengan nilai nol dan baris kelima menyebabkan ini melompati indeks itu.
David Brunow
1

Anda dapat menggunakan Array.sort menggunakan fungsi kustom sebagai parameter untuk menentukan mekanisme penyortiran Anda.

Dalam contoh Anda, itu akan memberikan:

var Data = [
    {id_list:1, name:'Nick',token:'312312'},{id_list:2,name:'John',token:'123123'}
]

Data.sort(function(a, b){
    return a.name < b.name ? -1 : a.name > b.name ? 1 : 0;
});

alert("First name is : " + Data[0].name); // alerts 'John'
alert("Second name is : " + Data[1].name); // alerts 'Nick'

Fungsi sortir harus mengembalikan -1 jika a datang sebelum b, 1 jika a datang setelah b dan 0 jika keduanya sama. Terserah Anda untuk menentukan logika yang tepat dalam fungsi pengurutan Anda untuk mengurutkan array.

Sunting: Tidak terjawab bagian terakhir dari pertanyaan Anda di mana Anda ingin mengetahui indeks. Anda harus mengulang-ulang array untuk menemukan bahwa seperti yang orang lain katakan.


sumber
1

Cukup telusuri array Anda dan temukan posisi:

var i = 0;
for(var item in Data) {
    if(Data[item].name == 'John')
        break;
    i++;
}
alert(i);
Sascha Galley
sumber
Ini seharusnya if(Data[item].name == 'John'), saya memperbaikinya untuk Anda.
Rocket Hazmat
Ini ada satu momen. Jika variabel 'tidak ditemukan' saya mengandung indeks positif. Dan untuk menguji 'tidak ditemukan' perlu membandingkan jika saya === Data.length
Andrew D.
Momen kedua adalah jika array berisi properti kustom bukan indeks. Sebagai contoh: var Data [1,2,3,4,5]; Data ["test"] = 7897; Bandingkan keluaran dari: untuk peringatan (var i di Data) (Data [i]); dan untuk peringatan (var i = 0; i <Data.length; i ++) (Data [i]);
Andrew D.
1

Mengapa Anda tidak menggunakan pekerjaan kecil?

Buat array baru dengan nama sebagai indeks. setelah itu semua pencarian akan menggunakan indeks. Jadi, hanya satu putaran. Setelah itu Anda tidak perlu mengulang semua elemen!

var Data = [
    {id_list:1, name:'Nick',token:'312312'},{id_list:2,name:'John',token:'123123'}
    ]
var searchArr = []
Data.forEach(function(one){
  searchArr[one.name]=one;
})
console.log(searchArr['Nick'])

http://jsbin.com/xibala/1/edit

contoh hidup.


sumber
Itu berarti mengulang semuanya terlebih dahulu ... kemudian memodifikasi objek (kecuali Anda mengkloningnya tetapi itu lebih mahal). Dan setelah itu Anda mengulang lagi (setidaknya sebagian).
Jos
1

Jawaban Chris Pickett yang diperluas karena dalam kasus saya, saya perlu mencari lebih dalam dari satu level atribut:

function findWithAttr(array, attr, value) {
  if (attr.indexOf('.') >= 0) {
    var split = attr.split('.');
    var attr1 = split[0];
    var attr2 = split[1];
    for(var i = 0; i < array.length; i += 1) {
      if(array[i][attr1][attr2] === value) {
        return i;
      }
    }
  } else {
    for(var i = 0; i < array.length; i += 1) {
      if(array[i][attr] === value) {
        return i;
      }
    }
  };
};

Anda dapat melewatkan 'attr1.attr2' ke dalam fungsi

Ed Shee
sumber
1

Bagaimana dengan ini ? :

Data.indexOf(_.find(Data, function(element) {
  return element.name === 'John';
}));

Dengan asumsi Anda menggunakan lodash atau underscorejs.

Ellone
sumber
1
var fields = {
teste:
{
    Acess:
    {
        Edit: true,
      View: false

      }
 },
teste1:
{
    Acess:
    {
        Edit: false,
      View: false

      }
  }
};

console.log(find(fields,'teste'));
function find(fields,field){
    for(key in fields){
        if(key == field){
        return true;
    }
}
return false;
}

Jika Anda memiliki satu Objek dengan banyak objek di dalamnya, jika Anda ingin tahu jika beberapa objek disertakan pada objek Master, cukup cantumkan find (MasterObject, 'Object to Search'), fungsi ini akan mengembalikan respons jika ada atau tidak (BENAR atau SALAH) ), Saya harap membantu dengan ini, dapat melihat contoh di JSFiddle .

Pedro Monteiro Arantes
sumber
Tambahkan beberapa penjelasan dengan jawaban untuk bagaimana jawaban ini membantu OP dalam memperbaiki masalah saat ini
ρяσѕρєя K
@ ρяσѕρєяK, Terima kasih atas saran Anda, saya sudah menambahkan penjelasannya :)
Pedro Monteiro Arantes
1
let indexOf = -1;
let theProperty = "value"
let searchFor = "something";

theArray.every(function (element, index) {

    if (element[theProperty] === searchFor) {
        indexOf = index;
        return false;
    }
    return true;
});
Itay Merchav
sumber
1
collection.findIndex(item => item.value === 'smth') !== -1
Eugene Lyzo
sumber
Sementara potongan kode ini dapat menyelesaikan pertanyaan, termasuk penjelasan sangat membantu untuk meningkatkan kualitas posting Anda. Ingatlah bahwa Anda menjawab pertanyaan untuk pembaca di masa depan, dan orang-orang itu mungkin tidak tahu alasan untuk saran kode Anda. Cobalah juga untuk tidak membuat kerumunan kode Anda dengan komentar penjelasan, karena ini mengurangi keterbacaan kode dan penjelasannya!
Selamat tinggal StackExchange
1

Jika Anda ingin mendapatkan nilai token properti maka Anda juga dapat mencoba ini

    let data=[
      { id_list: 1, name: 'Nick', token: '312312' },
      { id_list: 2, name: 'John', token: '123123' },
    ]

    let resultingToken =  data[_.findKey(data,['name','John'])].token

di mana _.findKey adalah fungsi lodash

Akash Singh
sumber
0

Atau sebagai pengganti jawaban German Attanasio Ruiz, Anda dapat menghilangkan loop ke-2 dengan menggunakan Array.reduce () alih-alih Array.map ();

var Data = [
    { name: 'hypno7oad' }
]
var indexOfTarget = Data.reduce(function (indexOfTarget, element, currentIndex) {
    return (element.name === 'hypno7oad') ? currentIndex : indexOfTarget;
}, -1);
hypno7oad
sumber
-1

Menggunakan garis bawah:

var index = _.indexOf(_.pluck(item , 'name'), 'Nick');
M Faisal Hameed
sumber