Bir nesne dizisindeki indexOf yöntemi?


513

Nesneler içeren bir dizinin dizinini almanın en iyi yöntemi nedir?

Bu senaryoyu düşünün:

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

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

Şimdi , bu örnekte indexOfhangi helloözelliğin olduğu nesneye sahip 'stevie'olmak istiyorum 1.

JavaScript ile oldukça yeni başlıyorum ve basit bir yöntem olup olmadığını veya bunu yapmak için kendi işlevimi oluşturmak gerekir bilmiyorum.


1
Eğer iki nesne birleştirmek istiyorsunuz hellove qaz?
Armin

Hayır, bilmiyorum. Bir dizideki nesnelerin bir listesini almak istiyorum.
Antonio Laguna

Ah tamam! Tanımlı bir özelliğe sahip dizideki tüm nesnenin konumunu bilmek istersiniz.
Armin

10
Bu SO cevabı ile bu tam sorunu çözmek için çok basit bir fonksiyon buldum: var elementPos = array.map(function(x) {return x.id; }).indexOf(idYourAreLookingFor); var objectFound = array[elementPos]; [link] ( stackoverflow.com/a/16100446/1937255 )
Rick

ES6 Array.indexOf kabul edilen yanıttan daha iyi (ES6 sizin için çalışıyorsa) - aşağıdaki tam örneğe bakın
yar1

Yanıtlar:


1043

Harita işlevini kullanarak tek bir satırda çözebileceğinizi düşünüyorum :

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

58
Bu dürüstçe kabul edilen cevap olmalıdır. Günümüzde çoğu tarayıcı desteğiArray.prototype.map()
AlbertEngelB

10
IE8 tarafından desteklenmiyor, ancak bu bir sorun değilse, bu en iyi çözümdür.
Antonio Laguna

57
Um ... Array.prototype.map () öğesinin, eşlenen öğeleri içeren tamamen yeni bir dizi oluşturduğunu belirtmeye değmez mi? Yani, 1000 öğeden oluşan bir diziniz varsa, önce 1000 öğeden oluşan başka bir dizi oluşturdunuz , sonra arama? Bu yöntemin performansını basit bir döngü için görmeyi düşünüyorum. Özellikle sınırlı kaynaklara sahip bir mobil platformda çalışırken.
Doug

7
@Doug Performansla ilgili noktanız gerçekten doğru olsa da, sağ akıllarında kim darboğazlar için profilli olana kadar neredeyse tanım IO / Network'e bağlı bir uygulama için bir kod satırını yedi ile değiştirir?
Jared Smith

6
Teknik olarak küçültülmüş bir js dosyası da bir satırdır; D
büyükKing

371

Array.prototype.findIndex , IE (kenar dışı) dışındaki tüm tarayıcılarda desteklenir. Ancak sağlanan çoklu dolgu güzel.

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

Harita ile çözüm tamam. Ancak her aramada tüm diziyi yineliyorsunuz. Bu sadece bir eşleşme bulunduğunda tekrarlamayı durduran findIndex için en kötü durumdur .


Gerçekten kısa bir yol yok (devs IE8 hakkında endişelenmek zorunda kaldığında) , ancak burada ortak bir çözüm var:

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

veya bir işlev olarak:

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

Sadece bazı notlar:

  1. Dizilerdeki döngülerde kullanmayın
  2. "İğnenizi" bulduğunuzda döngüden çıktığınızdan veya işlevden çıktığınızdan emin olun.
  3. Nesne eşitliğine dikkat edin

Örneğin,

var a = {obj: 0};
var b = [a];
b.indexOf({obj: 0}); // -1 not found

işlev searchTerm olması gerektiği gibi searchterm karşılaştırması yanlış :)
Antonio Laguna

birden fazla olay oldu
Joe

3
@SteveBennett performans için optimize edilmiş bir versiyonudur; dizinin uzunluğu yalnızca bir kez belirlenmelidir (for-loop değişkenleri başlatıldığında). Sizin durumunuzda, uzunluk her yinelemeyi yeniden kontrol eder. Ayrıca bkz. Stackoverflow.com/questions/5349425/… ve stackoverflow.com/questions/8452317/… Ancak, performans yüksek prio değilse gerçekten önemli değildir.
15'te loother

1
İyi bir yanıt, ancak bazı performans kıyaslamaları yaptım (bkz. Jsperf.com/find-index-of-object-in-array-by-contents ) ve burada belirtilen fonksiyon tabanlı cevabın ikinci en performanslı cevap olduğunu gördüm . Belirtildiği gibi tek şey yukarı daha fazla ölçülebilir uçları, bunun yerine sadece bir fonksiyonun, bir prototip içine koyarak ediliyor Cevabıma .
Uniphonic

123

ES2015'te bu oldukça kolaydır:

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

veya büyük diziler için muhtemelen daha iyi performansla:

myArray.findIndex(x => x.hello === 'stevie')

2
ES6'yı kullanmak için iyi bir yaklaşım
kag

Cevabımda belirtildiği gibi, bu yöntemlerin hiçbirinin döngü prototipi kadar performanslı olmadığına şaşırdım. FindIndex yöntemi tarayıcı desteği biraz zayıf olsa da, aynı şeyi yapıyor gibi görünüyor, ancak yine de daha az performansla sonuçlanıyor mu? Kıyaslamalar için cevabımdaki bağlantıya bakın.
Uniphonic

Performans eldeki görev için önemliyse bilmek güzel. Çok nadiren, benim tecrübelerime göre, ama ymmv.
Steve Bennett

24
var idx = myArray.reduce( function( cur, val, index ){

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

}, -1 );

17

Pablo'nun cevabını seviyorum, ancak Array # indexOf ve Array # haritası tüm tarayıcılarda çalışmıyor. Alt çizgi mevcutsa yerel kodu kullanır, ancak yedekleri de vardır. Ayrıca, Pablo'nun anonim harita yönteminin tam olarak ne yaptığını yapmak için pluck yöntemine sahiptir.

var idx = _.chain(myArray).pluck("hello").indexOf("Stevie").value();

1
Array.prototype.map () IE9 + için soported ve IE8, 7, 6 için bir Polyfill kullanabilirsiniz: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Johann Echavarria

1
Bir çoklu dolgu kullanabilirsiniz. . . ya da temelde bir sürü başka güzellik eklenmiş çoklu dolgular olan alt çizgi ya da lodash kullanabilirsiniz . Alt çizgiyle itiraz nedir? Boyut?
tandrewnichols

Underscore'u gerçekten seviyorum, cevabınız da akıllı, ama IMHO Pablo'nun cevabı en temiz.
Johann Echavarria

Vay canına böyle zincirleme kullanmayı hiç düşünmemiştim. Aramayı akıcı hale getirmeyi gerçekten seviyorum.
Dylan Pierce

chainburada gereksiz. _.pluck(myArray, 'hello').indexOf('stevie')
Steve Bennett

14

Veya prototip oluşturun:

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

9
Çok uygun! Her ne kadar exisitng Array.indexOf yöntemine müdahale etmemek için prototype.indexOfObject'i seçsem de. 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
Ben kendi kendini yürütme kapanış eski ile önceden saklanan, değiştirme fonksiyonunun ilk satırı boyunca bir şey olmak ile sarın if (typeof property === 'string' || typeof property === 'number' || typeof property === 'boolean') return oldIndexOf(property, value);. Çünkü bunlar değişmez olan az sayıdaki türdür. Ayrıca gerekirse yerel yönteme yedek etkinleştirmek için üçüncü bir argüman özelliği olacaktır.
Isiah Meadows

8

Kısa

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

Kullanım Durumları:

  /*****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);
      }
    };

6

Herkesin kendi kendine çalıştırabileceği çeşitli cevapların bazı performans testlerini yaptım:

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

Chrome'daki ilk testlerime dayanarak, aşağıdaki yöntem (bir prototipin içinde for for döngüsü kullanarak) en hızlı yöntemdir:

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

Bu kod Nathan Zaetta'nın cevabının biraz değiştirilmiş bir versiyonudur.

Performans ölçütlerinde, 1000 nesne dizisinin ortası (dizin 500) ve en sonunda (dizin 999) olması ve denemeyi dizideki son öğe olarak koysam bile (yani dizideki her öğeyi bulmadan önce döngü yapması gerekir) yine de en hızlı şekilde sonuçlanır.

Bu çözüm aynı zamanda tekrar tekrar yürütmek için en çok sıradan olanı olma avantajına sahiptir, çünkü sadece son satırın tekrarlanması gerekir:

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

2
Bu soruya kendi testlerimle bir keman kullanarak cevap vermek üzereydim, ancak cevabınız sayesinde artık zorunda değilim. Sadece testlerinizi onaylamak istiyorum - aynı sonucu aldım, ama bir whileyerine bir döngü kullanarak forve performance.now(). Bu cevabın daha fazla değerlendirilmesini ve daha önce görmemi isterdim, bu beni biraz zaman kazandıracaktı ...
Yin Cognyto


5

Buradaki diğer cevapların çoğu geçerlidir. Bazen, kullanacağınız yere yakın kısa bir basit işlev yapmak en iyisidir.

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

Sizin için neyin önemli olduğuna bağlıdır. Kod satırlarını kaydedebilir ve bir astar kullanmak veya çeşitli kenar durumlarını kapsayan bir yere genel bir çözüm koymak çok akıllı olabilir. Ancak bazen, gelecekteki geliştiricilerin ekstra ters mühendislik çalışması yapmasını bırakmak yerine, "burada böyle yaptım" demek daha iyidir. Özellikle kendinizi sorunuzdaki gibi bir "acemi" olarak görüyorsanız.


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

Dikkat et [0].

Cevabında olduğu reducegibi kullanmak uygun Antonio Laguna.

Kısa özür dileriz ...


4

Nesneniz dizi içinde kullandığınız nesnelerle aynı ise, nesnenin dizinini, bir dize gibi yaptığınız gibi almanız gerekir.

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

Bu, IndexOf'un değere veya neye göre eşleşip eşleşmediği benim için belirsiz olduğu için aradığım cevaptı. Şimdi benim nesne bulmak için IndexOf kullanabilirsiniz biliyorum ve aynı özelliklere sahip başka nesneler varsa endişelenmeyin.
0:13


3

basit:

myArray.indexOf(myArray.filter(function(item) {
    return item.hello == "stevie"
})[0])

3

Sadece pozisyon bulmakla ilgileniyorsanız @ Pablo'nun cevabına bakınız .

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

Bununla birlikte, öğeyi bulmayı dört gözle bekliyorsanız (örneğin, böyle bir şey yapmayı düşünüyorsanız myArray[pos]), bunu kullanmanın daha etkili bir tek satır yolu vardır filter.

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

Performans sonuçlarına bakın (~ +% 42 ops / sn): http://jsbench.github.io/#7fa01f89a5dc5cc3bee79abfde80cdb3


2

Bu örneğe bakın: http://jsfiddle.net/89C54/

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

Sıfırla saymaya başlar.


2

Aşağıdaki kod ve herhangi bir nesne için çalışır kontrol etmek için genel bir işlev yaptık

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

İlk uyarı -1 döndürür (eşleşme bulunamadı anlamına gelir) ve ikinci uyarı 0 döndürür (eşleşme bulunur anlamına gelir).



2

ES6 findIndexyöntemini kullanarak, lodash veya başka bir kitaplık olmadan şunları yazabilirsiniz:

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

Bu, nesnenin anlık özelliklerini karşılaştırır, ancak özelliklere geri dönmez.

Uygulamanız findIndexhenüz sağlamazsa (çoğu sağlamaz), bu aramayı destekleyen hafif bir çoklu dolgu ekleyebilirsiniz:

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

( bu dupe'deki cevabımdan )


2

Array.prototype.findIndex()Temel olarak yerel ve kullanışlı bir işlev kullanabilirsiniz :

Dizideki bir öğe sağlanan test işlevini karşılıyorsa, findIndex () yöntemi dizideki bir dizini döndürür. Aksi takdirde -1 döndürülür.

Internet Explorer, Opera ve Safari'de desteklenmediğini ancak aşağıdaki bağlantıda sağlanan bir Çoklu Dolgu kullanabilirsiniz.

Daha fazla bilgi:

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


2

Arasında Furthor @Monika Garg cevap kullanabileceğiniz findIndex()(bir yoktur polyfill unsupprted tarayıcılar için).

İnsanların bu cevabı düşürdüğünü gördüm ve umarım bunu yanlış sözdizimi nedeniyle yapmışlardır, çünkü bence bu en zarif yoldur.

Dizideki bir öğe sağlanan test işlevini karşılıyorsa, findIndex () yöntemi dizideki bir dizini döndürür. Aksi takdirde -1 döndürülür.

Örneğin:

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


Yöntem zarif görünüyor, ancak MDN'ye göre IE desteği yok mu? developer.mozilla.org/tr/docs/Web/JavaScript/Reference/…
Jaakko Karhu

Çoklu dolguyu (yanıttaki bağlantı) kullanmaya çalışın.
Mosh Feu

1

Nesnenin dizinini dizide bulmanın yolu budur

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

0

Bu özel kod olmadan çalışır

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

Not: Bu gerçek dizini vermez, yalnızca nesnenizin geçerli veri yapısında bulunduğunu söyler


1
Bu herhangi bir endeks alınmasına izin vermediği için geçerli değil
Antonio Laguna

0

Sadece kullanabilirsiniz

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

Alt çizgi yok, hayır, sadece bir indirim.


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

Array yöntemini kullanın.
user3235365


-2

findIndex()Yöntemi kullanmayı tercih edeceğim :

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

index size endeks numarasını verecektir.


1
Cevap, Yazım ve Kod girintisi ve :) yanlış mı?
Sachin Verma

1
findIndex herhangi bir javascript standart uygulamasında değildir. Böyle bir yöntem için yaklaşan (ecma 6) bir teklif var, ancak imzası böyle değil. Lütfen ne demek istediğinizi açıklayın (belki yöntemin adı), findIndex yöntem bildirimini verin veya kullandığınız kütüphaneyi adlandırın.
Sebastien
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.