Bir nesne dizisinde, öznitelikleri bir aramayla eşleşen bir nesnenin dizinini bulmanın en hızlı yolu


135

Bunu yapmak için etkili bir yol bulmaya çalışırken biraz sörf yapıyorum, ama hiçbir yere ulaşmadım. Ben böyle görünüyor nesneleri bir dizi var:

array[i].id = some number;
array[i].name = some name;

Ne yapmak istiyorum id, örneğin 0,1,2,3 veya 4'e eşit olduğu nesnelerin INDEXES bulmaktır. Ben sadece gibi bir şey yapabilirim varsayalım:

var indexes = [];
for(i=0; i<array.length; i++) {
  (array[i].id === 0) ? { indexes[0] = i }
  (array[i].id === 1) ? { indexes[1] = i }
  (array[i].id === 2) ? { indexes[2] = i }
  (array[i].id === 3) ? { indexes[3] = i }
  (array[i].id === 4) ? { indexes[4] = i }
}

Bu işe yarar olsa da, özellikle array.length büyük olabilirse, oldukça pahalı ve yavaş (çirkin bahsetmiyorum) gibi görünüyor. Bunu biraz ladinlemek hakkında bir fikrin var mı? Ben bir şekilde array.indexOf kullanmayı düşündüm ama sentaks zorlamak nasıl görmüyorum. Bu

array.indexOf(this.id === 0);

örneğin, muhtemelen olması gerektiği gibi tanımsız döndürür. Şimdiden teşekkürler!


1
Düz eski bir diziniz varsa, tek yapmanız gereken yinelemektir. Diziler budur, dizi indeksine göre sıralanmış bir grup nesne.
Dave Newton

2
Bugün bu yazıyla karşılaşın, tüm geç gelenler için Array.prototype.findIndex()ECMAScript 2015'te yeni bir dizi yöntemi var . Kabul edilen cevap harika oldu.
Conrad Lo

Ben ES6 sözdiziminin hayranıyım (eski tarayıcılarda destek gerekiyorsa çoklu dolgu kullanın). ES7 + ES8 gelecek olacak
Fr0zenFyr

Yanıtlar:


391

Belki "harita" gibi daha üst düzey fonksiyonları kullanmak istersiniz. 'Alan' özelliğine göre arama yapmak istediğinizi varsayarsak:

var elementPos = array.map(function(x) {return x.id; }).indexOf(idYourAreLookingFor);
var objectFound = array[elementPos];

9
Bu cevap harika çünkü aslında endeksi sağlayarak soruyu cevaplıyor :)
Karşılık

3
@ZeroAbsolute Uygulanan işleviniz (haritaya aktarıldı), ölçütleriniz tarafından verilen her olası kombinasyon için benzersiz bir anahtar sağlayacak bir karma dizesi döndürebilir. Örneğin: function hashf(el) { return String(el.id) + "_" + String(el.name); }. Bu sadece bir ipucu: elementPos = array.map(hashf(x)).indexOf(hash({id:3, name:'Pablo'}));Açıkçası, sağladığım hash fonksiyonu tüm durumlar için geçerli değil çünkü '_'değerlerinizin bir parçasını oluşturabilir, ancak farklı hash yöntemlerini anlayabileceğiniz hızlı bir örnektir.
Pablo Francisco Pérez Hidalgo

1
Bulunmazsa bu ne döndürür? -1 diyorum, sadece merak ediyorum. Deneyeceğim.
Nathan C. Tresch

1
@ NathanC.Tresch -1 döndürür, çünkü indexOfbelirli bir değeri bulamadığında bu dönüş değeridir.
Pablo Francisco Pérez Hidalgo

2
Herkese merhaba iki yöntem kullanmak yerine map, indexOfsadece bir tane kullanabilirsiniz findIndex....... Örn:[{id:1},{id:2},{id:3},{id:4}].findIndex(function(obj){return obj.id == 3}) OR [{id:1},{id:2},{id:3},{id:4}].findIndex(obj => obj.id == 3)
Umair Ahmed

64

Dizideki öğe dizinini bulmanın en basit ve en kolay yolu.

ES5 sözdizimi: [{id:1},{id:2},{id:3},{id:4}].findIndex(function(obj){return obj.id == 3})

ES6 sözdizimi: [{id:1},{id:2},{id:3},{id:4}].findIndex(obj => obj.id == 3)


4
Bunun en şık çözüm olduğuna inanıyorum. Geriye dönük uyumluluktan endişe duyanlar için çoklu dolguyu developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…findIndex adresinde bulabilirsiniz
mrogers

2
ES6 tiftik aracımda, obj.id == 3burada kullanılan operatörün beklenmedik tip dönüşümüne neden olabileceğine dair bir uyarı alıyorum , bu nedenle obj.id === 3eşit değer ve türü test eden operatörü kullanın.
thclark

1
Bu cevap yukarıdaki kabul edilen cevaptan en az 3,5 kat daha hızlıdır. Kullanarak var elementPos = array.map(function(x) {return x.id; }).indexOf(idYourAreLookingFor);0.03500000002532033 milisaniye aldı Bunu kullanarak [{id:1},{id:2},{id:3},{id:4}].findIndex(obj => obj.id == 3)0.00999999747378752 milisaniye sürdü.
Ovidio Reyna

1
Bu CEVAP tüm diziyi yinelemediğinden en ETKİLİDİR. Seçilen cevap, tüm diziyi eşler ve sonra bir kez tüm dizi boyunca yinelemeye bağlı olan findIndex'i gösterir
Karun

26

Yeni Array yöntemi .filter () bunun için iyi çalışır:

var filteredArray = array.filter(function (element) { 
    return element.id === 0;
});

jQuery bunu .grep () ile de yapabilir.

edit: bu işlevlerin her ikisi de sadece başlık altında yinelenen, aralarında fark edilir bir performans farkı olmayacak ve kendi filtre işlevini haddeleme, ama neden tekerleği yeniden icat bahsetmeye değer.


+1, nesnelerde böyle yerleşik işlevleri her zaman unuturum.
Tejs

59
Bu bir dizin döndürmez.
Adam Grant

Bu bu soruya cevap vermiyor, ama bana çok yardımcı oluyor! Teşekkürler!
rochasdv

Bu dizin döndürmez.
Zengin

10

Performansı önemsiyorsanız, bul veya filtrele veya harita veya yukarıda tartışılan yöntemlerden herhangi birini kullanmayın

İşte en hızlı yöntemi gösteren bir örnek. HERE gerçek testin bağlantısıdır

Kurulum bloğu

var items = []

for(var i = 0; i < 1000; i++) {
    items.push({id: i + 1})
}

var find = 523

En Hızlı Yöntem

var index = -1
for(var i = 0; i < items.length; i++) {
    if(items[i].id === find) {
        index = i;
        break;
    }
}

Yavaş Yöntemler

items.findIndex(item => item.id === find)

YAVAŞ yöntem

items.map(item => item.id).indexOf(find);

2
Bu karşılaştırmayı sağladığınız için teşekkürler! Süper ilginç olan, performansın ne kadar değiştiğidir - hangi yöntemin daha hızlı değiştiği de dahil olmak üzere, bunları çalıştırmak için hangi tarayıcı / JavaScript motorunun kullanıldığına bağlı olarak değişir.
Iain Collins

1
Bunun bir cevap olarak işaretlenmesi gerektiğini düşünüyorum. Bu en hızlı ve yavaş olanları gösterir.
Ağrı kesici

Karşılaştırmanızda, blok 2 (findIndex kullanarak) aslında benim için daha hızlı (Microsoft Edge Chromium 83.0.474.0'da)
rezadru

Block 2 artık
kromda

8
array.forEach(function (elem, i) {  // iterate over all elements of array
    indexes[elem.id] = i;           // take the found id as index for the
});                                 // indexes array and assign i

sonuç, kimlik için bir arama listesidir. verilen kimlikle kaydın dizinini alırız.


6
var indices = [];
var IDs = [0, 1, 2, 3, 4];

for(var i = 0, len = array.length; i < len; i++) {
    for(var j = 0; j < IDs.length; j++) {
        if(array[i].id == ID) indices.push(i);
    }
}

6

Normal diziyi kullanarak yanıt gelmediğinden find:

var one = {id: 1, name: 'one'};
var two = {id: 2, name:'two'}
var arr = [one, two] 

var found = arr.find((a) => a.id === 2)

found === two // true

arr.indexOf(found) // 1

3

ES6 mapişlevini kullanma :

let idToFind = 3;
let index = someArray.map(obj => obj.id).indexOf(idToFind);

3

ES6 kullanarak yeni bir yol

let picked_element = array.filter(element => element.id === 0);

picked_elementbu durumda bir dizi ...
Heretic Monkey

3

const index = array.findIndex(item => item.id === 'your-id');

Bu, id === id-id ile dizideki öğenin dizinini almalıdır

array = [ {id:1}, {id:2} ];

const index = array.findIndex(item => item.id === 2);

console.log(index);


2

Test etmek için geri aramayla basit bir yineleyici oluşturabileceğiniz gibi geliyor. Bunun gibi:

function findElements(array, predicate)
{
    var matchingIndices = [];

    for(var j = 0; j < array.length; j++)
    {
        if(predicate(array[j]))
           matchingIndices.push(j);
    }

    return matchingIndices;
}

Sonra şöyle çağırabilirsiniz:

var someArray = [
     { id: 1, text: "Hello" },
     { id: 2, text: "World" },
     { id: 3, text: "Sup" },
     { id: 4, text: "Dawg" }
  ];

var matchingIndices = findElements(someArray, function(item)
   {
        return item.id % 2 == 0;
   });

// Should have an array of [1, 3] as the indexes that matched

2

Tejs'in cevabını mongoDB ve Robomongo I için uyarlama değişti

matchingIndices.push(j);

için

matchingIndices.push(NumberInt(j+1));

2

Yukarıdaki tüm harika cevabı ve cevabımın ekini özetlemek için yorumun bir kısmından tüm endeksleri bul.

  1. İlk oluşumun dizinini döndürmek için.

const array = [{ id: 1 }, { id: 2 }, { id: 3 }, { id: 4 }, { id: 2 }];
const idYourAreLookingFor = 2;

//ES5 
//Output: 1
array.map(function (x) { return x.id; }).indexOf(idYourAreLookingFor);

//ES6 
//Output: 1
array.findIndex(obj => obj.id === idYourAreLookingFor);

  1. Reduce kullanarak, tüm oluşumların dizin dizisini döndürmek için.

const array = [{ id: 1 }, { id: 2 }, { id: 3 }, { id: 4 }, { id: 2 }]
const idYourAreLookingFor = 2;

//ES5
//Output: [1, 4]
array.reduce(function (acc, obj, i) {
  if (obj.id === idYourAreLookingFor)
    acc.push(i);
  return acc;
}, []);

//ES6
//Output: [1, 4]
array.reduce((acc, obj, i) => (obj.id === idYourAreLookingFor) ? acc.concat(i) : acc, [])


0

Henüz yorum yapamadığım için, Umair Ahmed'in yayınladığı yönteme göre kullandığım çözümü göstermek istiyorum, ancak bir değer yerine bir anahtar aramak istediğinizde:

[{"a":true}, {"f":true}, {"g":false}]
.findIndex(function(element){return Object.keys(element)[0] == "g"});

Genişletilmiş soruya cevap vermediğini anlıyorum, ancak başlık her nesneden ne istediğini belirtmiyor, bu yüzden gelecekte baş ağrısını kurtarmak için bunu alçakgönüllülükle paylaşmak istiyorum. en hızlı çözüm.


0

O (1) karmaşıklığı ile benzersiz bir tanımlayıcı ile bir dizideki öğelere erişebileceğiniz süper dizi adı verilen küçük bir yardımcı program oluşturdum . Misal:

const SuperArray = require('super-array');

const myArray = new SuperArray([
  {id: 'ab1', name: 'John'},
  {id: 'ab2', name: 'Peter'},
]);

console.log(myArray.get('ab1')); // {id: 'ab1', name: 'John'}
console.log(myArray.get('ab2')); // {id: 'ab2', name: 'Peter'}

Sen okumak isteyebilirsiniz kişisel açık kaynak kütüphaneleri sunmak için nasıl? bunu her yere göndermeden önce.
Martijn Pieters

@MartijnPieters Ben sadece birkaç ilgili sorulara gönderdim ve proje MIT ücretsiz yani anlaşma nedir? Belki biraz daha hoşgörülü olabilirsin.
patotom

0
var test = [
  {id:1, test: 1},
  {id:2, test: 2},
  {id:2, test: 2}
];

var result = test.findIndex(findIndex, '2');

console.log(result);

function findIndex(object) {
  return object.id == this;
}

Dizin 1'i döndürecektir (Yalnızca ES 2016'da çalışır)


0

Bu yöntemi seviyorum çünkü ne kadar derin iç içe olursa olsun nesnedeki herhangi bir değerle karşılaştırmak kolaydır.

 while(i<myArray.length && myArray[i].data.value!==value){
  i++; 
}
// i now hows the index value for the match. 
 console.log("Index ->",i );
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.