Koşulla eşleşen bir dizinin içindeki nesnenin dizinini alma


322

Ben böyle bir dizi var:

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

Tüm diziyi yinelemeden, bir koşulla eşleşen nesnenin dizinini nasıl alabilirim?

Örneğin, verilen prop2=="yutu", dizin almak istiyorum 1.

Gördüm .indexOf()ama bunun gibi basit diziler için kullanıldığını düşünüyorum ["a1","a2",...]. Ben de kontrol $.grep()ama bu dizin değil, nesneleri döndürür.

Yanıtlar:


733

2016 itibariyle, bunun için Array.findIndex(bir ES2015 / ES6 standardı) kullanmanız gerekir:

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

console.log(index);

Google Chrome, Firefox ve Edge'de desteklenir. Internet Explorer için, bağlı sayfada bir çoklu dolgu var.

Performans notu

İşlev çağrıları pahalıdır, bu nedenle gerçekten büyük dizilerle basit bir döngü aşağıdakilerden çok daha iyi performans gösterir 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');

Çoğu optimizasyonda olduğu gibi, bu da dikkatli bir şekilde ve sadece gerçekten ihtiyaç duyulduğunda uygulanmalıdır.


3
Burada geçici bir dizi ihtiyacını görmüyorum. Yineleyici işlevinin bağlamı kapatması ve bir değişken kullanması yeterlidir. Ayrıca, jQuery olmayan sürüm çalışmaz (dizinde bulunduğunu varsayalım 0?). Her iki çözüm de gerektiğinden daha fazla yineleme yapar, bu da dizi büyükse idealden daha azdır (aramalar çok fazla olmadıkça, bir insanın fark edeceği kadar büyük olma ihtimali düşüktür ).
TJ Crowder

@ thg435: Hala basit bir kolun hile yapacağı bir Rube Goldberg makinesi olduğunu düşünüyorum. :-) Ama hey, işe yarıyor!
TJ Crowder

4
x => x.prop2=="yutu"FindIndex () ile nasıl çalıştığını açıklayabilir misiniz ?
Abhay Pai

5
@AbhayPai: aynıfunction(x) { return x.prop2=="yutu" }
georg

6
Poli dolguyu kullanma önerisini seviyorum. Ancak yazılan kod IE11'de bir ok / lambda işlevinin kullanılması nedeniyle çoklu dolguda bile başarısız oluyor. Olarak yeniden yazılı index = a.findIndex(function (x) { return x.prop2 == "yutu" })polyfill koduyla, FindIndex IE11 çalıştı böylece bu sorunu düzeltti
Rick Glos

26

Bir koşulla eşleşen nesnenin dizinini nasıl alabilirim (dizi boyunca yineleme olmadan)?

Yapamazsınız , bir şey dizi boyunca yinelenmelidir (en az bir kez).

Koşul çok değişirse, o zaman döngüye girip içindeki nesnelere bakıp koşulla eşleşip eşleşmediklerini görmeniz gerekir. Bununla birlikte, ES5 özelliklerine sahip bir sistemde (veya bir şim yüklerseniz), yineleme oldukça kısaca yapılabilir:

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

Bu, verdiğiniz işlev true değerine dönene kadar dizideki girdiler arasında dolaşan new (ish) Array#someişlevini kullanır . Verdiğim işlev, eşleşen girişin dizinini kaydeder, ardından trueyinelemeyi durdurmak için geri döner .

Veya elbette, sadece bir fordöngü kullanın . Çeşitli yineleme seçenekleriniz bu diğer yanıtta ele alınmıştır .

Ancak bu arama için her zaman aynı özelliği kullanacaksanız ve özellik değerleri benzersizse, yalnızca bir kez döngü oluşturabilir ve bunları eşlemek için bir nesne oluşturabilirsiniz:

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

(Veya yine bir fordöngü veya diğer seçeneklerinizden herhangi birini kullanabilirsiniz .)

Ardından, girişi bulmanız prop2 = "yutu"gerekirse bunu yapabilirsiniz:

var entry = prop2map["yutu"];

Ben buna "çapraz indeksleme" dizisi diyorum. Doğal olarak, girişleri kaldırır veya eklerseniz (veya prop2değerlerini değiştirirseniz ), eşleme nesnenizi de güncellemeniz gerekir.


Açıklama için teşekkürler! JQuery ile işaret çözüm thg435istediğim yaptı ...
amp

21

TJ Crowder'in söylediği gibi, her neyse bir çeşit gizli yineleme olacak, lodash ile bu olur:

var index = _.findIndex(array, {prop2: 'yutu'})

1
sadece endeksi elde etmek için çeşitli yollar arasında döngü yaparken, bulmak Endeksi en iyi çözüm, hatta ES6 yerel dizi yöntemleri içine kabul
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);

Ve temel dizi numaraları için de bunu yapabilirsiniz:

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

Dizide bir değer bulamazsa -1 elde edersiniz.


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

Dizinin tüm öğeleri üzerinde yineleme. Koşul eşleşmezse, dizini ve doğru veya yanlış değerini döndürür.

Önemli, true değerinin (veya boole sonucunun doğru olduğu bir değer) açık dönüş değeridir. Tek bir atama, 0 (Boolean (0) === false) içeren olası bir dizin nedeniyle hataya neden olmaz, ancak yinelemenin kesilmesini devre dışı bırakır.

Düzenle

Yukarıdakilerin daha da kısa bir versiyonu:

yourArray.some(function (elem, i) {
    return elem.prop2 === 'yutu' && ~(index = i);
});

~ Karakter ikinci pasajınızda ne yapar?
serkan

@serkan, bu bitwise DEĞİL| operatör, bir dizin varsa (-1 ile) bir doğruluk / falsy sonucu elde kısa bir sürümüdür .
Nina Scholz

teşekkürler Nina, ~ karakteri olmadan, kod olduğu gibi çalışır, değil mi?
serkan

@serkan, sorunuz net değil, ama olmadan ~böyle çalışmaz.
Nina Scholz

1
oh !!(index = 0)ve !!~(index = 0)gerçekten fark. Teşekkürler!
serkan

4

Sen kullanabilirsiniz Array.prototype.some () şu şekilde (diğer yanıtlar belirtildiği gibi):

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

4

Yukarıda birçok çözüm gördüm.

Burada bir dizi nesnesindeki arama metninin dizinini bulmak için harita işlevini kullanıyorum.

Cevabımı öğrenci verilerini kullanarak açıklayacağım.

  • 1. adım : öğrenciler için dizi nesnesi oluşturun (isteğe bağlı olarak kendi dizi nesnenizi oluşturabilirsiniz).
    var students = [{name:"Rambabu",htno:"1245"},{name:"Divya",htno:"1246"},{name:"poojitha",htno:"1247"},{name:"magitha",htno:"1248"}];

  • 2. adım : Metin aramak için değişken oluşturma
    var studentNameToSearch = "Divya";

  • 3. adım : Eşleşen dizini depolamak için değişken oluşturun (burada yineleme için harita işlevini kullanıyoruz).
    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)


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);

1

Neden tam olarak tekrarlamak istemiyorsun? Yeni Array.prototype.forEach bu amaç için mükemmeldir!

İsterseniz tek bir yöntem çağrısı ile bulmak için bir İkili Arama Ağacı kullanabilirsiniz. Bu, BTree ve Red black Search ağacının JS'deki düzgün bir uygulamasıdır - https://github.com/vadimg/js_bintrees - ancak dizini aynı anda bulabileceğinizden emin değilim.


1

Array.reduce () kullanarak bir adım - jQuery yok

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);

nulldizin bulunmazsa geri döner .


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
}

0

Georg zaten ES6 bunun için Array.findIndex var bahsetti. Ve diğer bazı cevaplar Array.some yöntemi kullanılarak ES5 için geçici çözümdür.

Daha zarif bir yaklaşım

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

Aynı zamanda vurgulamak isteyeceğim, Array.some ikili veya diğer verimli arama tekniği ile uygulanabilir. Bu nedenle, bazı tarayıcılarda döngü için daha iyi performans gösterebilir.


0

Bu kodu deneyin

var x = [{prop1:"abc",prop2:"qwe"},{prop1:"bnmb",prop2:"yutu"},{prop1:"zxvz",prop2:"qwrq"}]
let index = x.findIndex(x => x.prop1 === 'zxvz')
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.