Bir dizi JavaScript nesnesinde kimliğe göre nesne bulma


1545

Bir dizim var:

myArray = [{'id':'73','foo':'bar'},{'id':'45','foo':'bar'}, etc.]

Dizinin yapısını değiştiremiyorum. Ben bir kimliği geçiriliyor ve dizideki bu nesne 45için almak istiyorum 'bar'.

Bunu JavaScript'te veya jQuery kullanarak nasıl yapabilirim?

Yanıtlar:


1187

find()Yöntemi kullanın :

myArray.find(x => x.id === '45').foo;

Gönderen MDN'yi :

find()Yöntem olup, dizideki ilk değerini verir dizi tatmin bir eleman temin test fonksiyonu ise. Aksi takdirde undefinediade edilir.


Bunun yerine dizinini bulmak istiyorsanız , şunu kullanın findIndex():

myArray.findIndex(x => x.id === '45');

Gönderen MDN'yi :

findIndex()Yöntem tatmin test fonksiyonu şu şartla ki dizideki ilk elemanın dizinini döndürür. Aksi takdirde -1 döndürülür.


Eşleşen öğeler dizisi almak istiyorsanız, filter()bunun yerine yöntemi kullanın:

myArray.filter(x => x.id === '45');

Bu bir dizi nesne döndürür. Bir dizi fooözellik almak istiyorsanız, bunu map()yöntemle yapabilirsiniz:

myArray.filter(x => x.id === '45').map(x => x.foo);

Yan not: gibi yöntemler find()veya filter(), ve ok fonksiyonları böylece bu tarayıcılar desteklemek istiyorlarsa, kullanmakta kodunuzu transpile gerektiğini (IE gibi) daha eski tarayıcılar tarafından desteklenmez Babel (ile Polyfill ).


2
Bu nedenle, birden fazla test koşulu için şöyle bir şey olur: myArray.find (x => x.id === '45' && x.color == 'kırmızı'). Foo
Apqu

2
Benim için şimdiye kadar en iyi cevap. JQuery ne de yeni yardımcı diziler oluşturmaz.
Canta

myArray.find (x => x.id === '45') mac PC'de çalışmıyor
Govinda Rajbhar

@TJCrowder Çok amaçlı dolguları MDN'den kodunuza kopyalayıp yapıştırmanın iyi bir fikir olduğunu düşünmüyorum; bunun yerine, çoklu dolgular içeren npm paketleri kullanmalısınız. Babel, babel-polyfill paketinde ES2015 + özellikleri için çoklu dolgular içerir .
Michał Perłakowski

2
myArray.find (x => x.id === '45'). foo; '45' kimliğine sahip bir nesne yoksa bir istisna atar.
Frazer Kirkman

1466

Zaten jQuery kullandığınız gibi, bir dizi aramak için tasarlanmış grep işlevini kullanabilirsiniz :

var result = $.grep(myArray, function(e){ return e.id == id; });

Sonuç, bulunan öğelerin bulunduğu bir dizidir. Nesnenin her zaman orada olduğunu ve yalnızca bir kez oluştuğunu biliyorsanız result[0].foo, değeri elde etmek için kullanabilirsiniz . Aksi takdirde, elde edilen dizinin uzunluğunu kontrol etmelisiniz. Misal:

if (result.length === 0) {
  // no result found
} else if (result.length === 1) {
  // property found, access the foo property using result[0].foo
} else {
  // multiple items found
}

124
JavaScript operatörünün garip sorunlarından kaçınmak ===yerine kullanmak daha güvenli olacaktır . ====
Vicky Chijwani

11
@VickyChijwani: Bir dizeyi bir dizeyle karşılaştırırken herhangi bir sorun var mı?
Guffa

38
Eğer buysa kesinlikle hem emin e.idve iddizeleri olacak, kullanımı 's OK varsayalım ==. Eğer emin değilseniz (çünkü Ama, sorunlar olabilir '' == 0olduğunu trueama '' === 0olan false). Bahsetmemek ===daha hızlı görünüyor ( stackoverflow.com/questions/359494/… ).
Vicky Chijwani

101
Temelde hep kullanmak ===çalışır çünkü tam gibi ==diğer programlama dillerinde. ==JavaScript'te var olmadığını düşünüyorum .
Vicky Chijwani

6
@de. Buradaki birçok cevap, benzersiz değerlere bakarken amaçlanan davranışı sağlar; temelde döngülerinden erken dönmeleri veya kopmaları gerçeğiyle tanıyabilirsiniz (veya daha düşük seviyeli bir yapıya yinelemeyi durdurmaları talimatı). Kanonik bir örnek için JaredPar'ın cevabına ve Aaronius'un aynı cevap için bu cevap hakkındaki yorumuna bakın. Genel olarak, insanlar bu şekilde "filtre" ve "bul" işlevleri arasında ayrım yapar, ancak terminoloji değişir. Daha verimli olmasına rağmen, bu hala doğrusal bir aramadır, bu nedenle bir karma tablo kullanmak istiyorsanız, Aaron Digulla'nın cevabına bakın (ayrıntılara dikkat edin).
tne

362

Başka bir çözüm, bir arama nesnesi oluşturmaktır:

var lookup = {};
for (var i = 0, len = array.length; i < len; i++) {
    lookup[array[i].id] = array[i];
}

... now you can use lookup[id]...

Birçok arama yapmanız gerekiyorsa bu özellikle ilginçtir.

Kimlikler ve nesneler paylaşılacağı için bunun daha fazla belleğe ihtiyacı yoktur.


6
Tam aradığım şey. Her seferinde döngü yapmaya çalışarak aşırı karmaşıklaştırmaya çalıştığım kadar komik, her öğeyi listeden kaldırarak, yalnızca CouchDB'den alınan verileri mutasyona uğratmak ve benim için yararlı bir biçime almak gerektiğinde buldum ihtiyacı vardır. +1 efendim!
slickplaid

5
bu akıllı. Diğerleri her kullanım için dizi üzerinden bakarak nasıl ikna olduğunu düşünemiyorum.
Aladdin Mhemed

4
Mülklerin sırasına güvenmediğiniz sürece: stackoverflow.com/questions/4886314/…
Marle1

Bir mola kullanıyor; döngüde iyi bir seçenek / iyileştirme bulmak için tek bir nesne olduğunu biliyorsanız?
irJvV

7
@irJvV: Hayır, bu hiç mantıklı değil. Çok sayıda arama yapmanız gerekiyorsa yukarıdaki kod kullanışlıdır. Sadece bir kez bakarsanız, bir lookupnesne oluşturmak zaman kaybıdır.
Aaron Digulla

174

ECMAScript 2015 , dizilerde find () yöntemini sağlar:

var myArray = [
 {id:1, name:"bob"},
 {id:2, name:"dan"},
 {id:3, name:"barb"},
]

// grab the Array item which matchs the id "2"
var item = myArray.find(item => item.id === 2);

// print
console.log(item.name);

Harici kütüphaneler olmadan çalışır. Ancak daha eski tarayıcı desteği istiyorsanız, bu çoklu dolguyu dahil etmek isteyebilirsiniz .


1
Muhtemelen hala çok deneysel göründüğünden ve pek çok tarayıcı desteklemediğinden, developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
lejonl

2
Bu basitleştirilebilir myArray.find(d=>d.id===45).foo;.
shaggy

1
@Shaggy veya hatta myArray.find(({ id }) => id === 45).foo. Ancak bu, ES2015 sözdiziminin şu ana kadar desteklenmesinden önce yazılmış eski bir cevaptır. @ Gothdo'nun cevabı şu anda konunun en güncel olanı.
Rúnar Berg

1
@ .Find () undefined değerini döndürürse, optimizasyonunuz bir hata verir. Bu nedenle, bu çözüm yalnızca bir eşleşmenin garanti edildiği durumlarda kullanılabilir.
Herbert Peters

1
Eğer olmak istiyorsan @HerbertPeters emin gerçekten kolay olacak boş-çek, Alway yapabilirsiniz isteğe bağlı zincirleme : myArray.find(d => d.id === 45)?.foo.
Rúnar Berg

141

Underscore.js bunun için güzel bir yöntem var:

myArray = [{'id':'73','foo':'bar'},{'id':'45','foo':'bar'},etc.]
obj = _.find(myArray, function(obj) { return obj.id == '45' })

42
Kayıt için, Lo-Dash (genellikle Underscore'dan daha fazla performans gösteren) benzer bir yönteme sahiptir. Dokümanlar burada: lodash.com/docs#find
user456584

Yalnızca bir nesne bekliyorsanız, findWhere kullanmak bir sonuç bulduktan sonra daha verimli olur, arama daha ileri gitmez.
2015'te

@Foreever _.find belgelerinden: "İşlev, kabul edilebilir bir öğe bulur bulmaz geri döner ve tüm listeyi geçmez."
GijsjanB

129

Bence en kolay yol şu olurdu, ancak Internet Explorer 8 (veya daha önceki sürümlerde) çalışmaz:

var result = myArray.filter(function(v) {
    return v.id === '45'; // Filter out the appropriate one
})[0].foo; // Get result and access the foo property

Merak ediyorum, burada her zamankinden daha fazla performans avantajı var formı?
Igor Zinov'yev

@Igor Zinov'yev: Evet, kesinlikle bu ES5 dizi araçlarıyla performans etkileri var. Her öğe için ayrı bir işlev yürütülür, bu nedenle doğrudan fordöngüye kıyasla gerçekten hızlı olmaz .
pimvdb

Yani bunun daha yavaş olacağını mı söylüyorsun? Ayrıca, her diziyi her zaman görebildiğim kadarıyla tararken, fordöngü ilk maçta sona erecek.
Igor Zinov'yev

IE8 için desteğe ihtiyacınız varsa, bunu şuraya bırakın: stackoverflow.com/questions/7153470/…
Adam Grant

Bununla ilgili bir öğe yoksa bu kod hata veririd
Stan

71

Takip etmeyi dene

function findById(source, id) {
  for (var i = 0; i < source.length; i++) {
    if (source[i].id === id) {
      return source[i];
    }
  }
  throw "Couldn't find object with id: " + id;
}

17
Bu kendi cevabına layık değildi, ancak modern tarayıcılarda bu çözüm şu şekilde yazılabilir: jsfiddle.net/rwaldron/j3vST
Rick

12
Verimlilik istiyorsanız, bu örneğin filter () kullanmaktan daha hızlı olduğunu unutmayın (Rick örneğine bakın), ilk eşleşen öğeyi bulduktan sonra geri dönerken filter (), eşleşme. Bu, ek bir dizi oluşturma veya her öğe için bir işlev çağırma maliyetine de sahip değildir.
Aaronius

3
@Rick, bu cevapla ilgili en ilginç şey, görünüşe göre firebug konsolunu jsFiddle'daki çıkış penceresine ekleyebilirsiniz. Bu, günlüğe kaydetmekten ve çıktıyı görmek için bir başkasına konsolu açmasını söylemekten çok daha iyidir. Müthiş!
KyleMit

1
Kimse şu ana kadar bahsetmediği için, AngularJS'nin de bir filtre yöntemi olduğunu eklemek istedim .
Eno



31

Yukarıdaki findById işlevinin genel ve daha esnek bir sürümü:

// array = [{key:value},{key:value}]
function objectFindByKey(array, key, value) {
    for (var i = 0; i < array.length; i++) {
        if (array[i][key] === value) {
            return array[i];
        }
    }
    return null;
}

var array = [{'id':'73','foo':'bar'},{'id':'45','foo':'bar'}];
var result_obj = objectFindByKey(array, 'id', '45');

15

Map () işlevini kullanarak bunu kolayca alabilirsiniz :

myArray = [{'id':'73','foo':'bar'},{'id':'45','foo':'bar'}];

var found = $.map(myArray, function(val) {
    return val.id == 45 ? val.foo : null;
});

//found[0] == "bar";

Çalışma örneği: http://jsfiddle.net/hunter/Pxaua/


1
mapJQuery'nin nullöğeleri otomatik olarak kaldırdığını unuttum . mapSonuç, orijinal koleksiyonla aynı uzunlukta olmadığından, bana ve ortak kavramına yanıltıcı geliyor .
MaxArt

14

Filtreleri kullanabilirsiniz,

  function getById(id, myArray) {
    return myArray.filter(function(obj) {
      if(obj.id == id) {
        return obj 
      }
    })[0]
  }

get_my_obj = getById(73, myArray);

1
@TobiasBeuving - Array.find () kullanan biri de düz JS'dir ve ilk bulmada durmalıdır, bu yüzden daha verimli olacaktır.
Adrian Lynch

12

Burada birçok doğru cevap olsa da, birçoğu birden fazla yapılırsa bunun gereksiz bir pahalı işlem olduğu gerçeğini ele almaz. Aşırı bir durumda, bu gerçek performans sorunlarının nedeni olabilir.

Gerçek dünyada, çok fazla öğe işliyorsanız ve performans bir endişe kaynağıysa, başlangıçta bir arama oluşturmak çok daha hızlıdır:

var items = [{'id':'73','foo':'bar'},{'id':'45','foo':'bar'}];

var lookup = items.reduce((o,i)=>o[i.id]=o,{});

daha sonra şu şekilde sabit zamanda ürün alabilirsiniz:

var bar = o[id];

Arama olarak nesne yerine bir Harita kullanmayı da düşünebilirsiniz: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Map


11

Yerli kullanma Array.reduce

var array = [ {'id':'73' ,'foo':'bar'} , {'id':'45' ,'foo':'bar'} , ];
var id = 73;
var found = array.reduce(function(a, b){
    return (a.id==id && a) || (b.id == id && b)
});

bulunursa nesne öğesini döndürür, aksi takdirde false


Sadece bir not, Array.reduce IE8 ve altında desteklenmez.
Burn_E99

7

Bunu birden çok kez yaparsanız, bir Harita (ES6) oluşturabilirsiniz:

const map = new Map( myArray.map(el => [el.id, el]) );

Sonra şunları yapabilirsiniz:

map.get(27).foo

6

ECMAScript 3 veya daha sonraki sürümlerde çalıştığını düşünebileceğim en az şekilde saf JavaScript ile nasıl başlayacağım. Bir eşleşme bulunur bulunmaz geri döner.

var getKeyValueById = function(array, key, id) {
    var testArray = array.slice(), test;
    while(test = testArray.pop()) {
        if (test.id === id) {
            return test[key];
        }
    }
    // return undefined if no matching id is found in array
    return;
}

var myArray = [{'id':'73', 'foo':'bar'}, {'id':'45', 'foo':'bar'}]
var result = getKeyValueById(myArray, 'foo', '45');

// result is 'bar', obtained from object with id of '45'

5

Daha genel ve kısa

function findFromArray(array,key,value) {
        return array.filter(function (element) {
            return element[key] == value;
        }).shift();
}

sizin durumunuzda Örn. var element = findFromArray(myArray,'id',45)size bütün elementi verecektir.


4

Sugarj'ları http://sugarjs.com/ adresinden deneyebilirsiniz. .

Dizilerde çok tatlı bir yöntemi var .find. Böylece böyle bir eleman bulabilirsiniz:

array.find( {id: 75} );

Başka bir "where-cümlesi" eklemek için daha fazla özelliğe sahip bir nesne de iletebilirsiniz.

Sugarjs'ın yerel nesneleri genişlettiğini ve bazı insanların bunu çok kötü düşündüğünü unutmayın ...


2
Eh, o ise yeni ECMAscript sürümleri aynı adla yeni yöntemler tanıtmak olabileceğini ortaya çıkabilir, çünkü kötülük. Ve tahmin et ne oldufind , tam olarak olan buydu . Benim önerim, yerel prototipleri genişletmek istiyorsanız, her zaman daha spesifik isimler kullanın ve en basit olanları gelecekteki standart gelişmelere bırakın.
MaxArt

Bu yorum neredeyse 2 yaşında ve bugün yine de lodash kullanmayı tercih ederim. Ancak isterseniz bu konu hakkında sugarjs web sitesinde okuyabilirsiniz. Düşünceleriniz için iyi bir tavır alıyorlar
deepflame

1
Op özellikle bir javascript veya jquery çözümü
istedi

4

Kabul edilen cevaba dayanarak:

jQuery:

var foo = $.grep(myArray, function(e){ return e.id === foo_id})
myArray.pop(foo)

Veya CoffeeScript:

foo = $.grep myArray, (e) -> e.id == foo_id
myArray.pop foo

4

Son zamanlarda, ben büyük bir dizeden dize aramak için gereken aynı şeyle yüzleşmek zorunda.

Biraz arama yaptıktan sonra basit kodla işlem yapmak kolay olacak:

Kod:

var items = mydata.filter(function(item){
    return item.word.toLowerCase().startsWith( 'gk );
})

Bkz. Https://jsfiddle.net/maheshwaghmare/cfx3p40v/4/

20k iplerden Serach


3

Dizideki herhangi bir öğenin üzerinde yineleme. Ziyaret ettiğiniz her öğe için o öğenin kimliğini kontrol edin. Bir eşleşme varsa, iade edin.

Sadece codez istiyorsanız:

function getId(array, id) {
    for (var i = 0, len = array.length; i < len; i++) {
        if (array[i].id === id) {
            return array[i];
        }
    }
    return null; // Nothing found
}

Aynı şey ECMAScript 5'in Array yöntemlerini kullanarak:

function getId(array, id) {
    var obj = array.filter(function (val) {
        return val.id === id;
    });

    // Filter returns an array, and we just want the matching item.
    return obj[0];
}

3

Tarayıcı ECMA-262 , 5. baskısını (Aralık 2009) desteklediği sürece , bu neredeyse bir astarlı çalışmalıdır:

var bFound = myArray.some(function (obj) {
    return obj.id === 45;
});

2
Neredeyse. bir öğe gerekli koşulu karşılarsa bFound, yalnızca bir boole truedeğeridir.
MaxArt

3

Diziler için yerleşik "filtre" işlevini kullanarak bunu saf JavaScript'te bile yapabilirsiniz:

Array.prototype.filterObjects = function(key, value) {
    return this.filter(function(x) { return x[key] === value; })
}

Yani şimdi yerine "id" ve yerine key"45" valueiletin ve tam nesnenin 45 id ile eşleşmesini sağlayın. Böylece,

myArr.filterObjects("id", "45");

16
Sahip olmadığınız nesneleri değiştirmeyin.
Michał Perłakowski

3

Array.prototype.filter()Fonksiyonu kullanın .

DEMO : https://jsfiddle.net/sumitridhal/r0cz0w5o/4/

JSON

var jsonObj =[
 {
  "name": "Me",
  "info": {
   "age": "15",
   "favColor": "Green",
   "pets": true
  }
 },
 {
  "name": "Alex",
  "info": {
   "age": "16",
   "favColor": "orange",
   "pets": false
  }
 },
{
  "name": "Kyle",
  "info": {
   "age": "15",
   "favColor": "Blue",
   "pets": false
  }
 }
];

FİLTRE

var getPerson = function(name){
    return jsonObj.filter(function(obj) {
      return obj.name === name;
    });
}

iç içe nesne içinde nasıl arama yapabilirim? Evcil hayvanlar gibi = false iki nesne döndürmelidir.
Valay

iç içe döngüde .filteryöntemi kullan obj.info. var getPerson = function(name){ return jsonObj.filter(function(obj) { return obj.info.filter(function(info) { return pets === false; }); }); }
Sumit Ridhal

es6 stilini de kullanabilirsiniz imo ... const filterData = jsonObj.filter (obj => obj.name === 'Alex')
DagicCross

3

Jquery yöntemlerini kullanabiliriz $.each()/$.grep()

var data= [];
$.each(array,function(i){if(n !== 5 && i > 4){data.push(item)}}

veya

var data = $.grep(array, function( n, i ) {
  return ( n !== 5 && i > 4 );
});

ES6 sözdizimini kullanın:

Array.find, Array.filter, Array.forEach, Array.map

Veya Lodash'ı kullanın https://lodash.com/docs/4.17.10#filter , Alt çizgi https://underscorejs.org/#filter


2

Aaron Digulla tarafından verilen cevabı gerçekten beğendim ama daha sonra tekrarlayabilmem için nesneler dizimi saklamam gerekiyordu. Ben de değiştirdim

	var indexer = {};
	for (var i = 0; i < array.length; i++) {
	    indexer[array[i].id] = parseInt(i);
	}
	
	//Then you can access object properties in your array using 
	array[indexer[id]].property


Dizideki öğeleri bulmak için en hızlı çözümle aynı çözümü kullandı. Ancak parseInt burada gereksizdir.
aleha

1

kullanın:

var retObj ={};
$.each(ArrayOfObjects, function (index, obj) {

        if (obj.id === '5') { // id.toString() if it is int

            retObj = obj;
            return false;
        }
    });
return retObj;

Bir nesneyi id ile döndürmelidir.


obj.id === 5 dönüş kodunu kullanarak kodunuzu kısaltabilirsiniz? obj: false; Diziler üzerinde yineleme yapmak için $ .each çok kullanıyorum.
marcel

@marcel: Bu işe yaramayacak. False döndürmek döngüyü sona erdireceğinden, nesneyi yalnızca dizideki ilk öğe olsaydı bulurdu.
Guffa

1

Bu çözüm de yardımcı olabilir:

Array.prototype.grep = function (key, value) {
    var that = this, ret = [];
    this.forEach(function (elem, index) {
        if (elem[key] === value) {
            ret.push(that[index]);
        }
    });
    return ret.length < 2 ? ret[0] : ret;
};
var bar = myArray.grep("id","45");

Tıpkı benim gibi yaptım $.grepve bir nesne bulunursa, işlev bir dizi yerine nesneyi döndürecektir.


2
Sahip olmadığınız nesneleri değiştirmeyin.
Michał Perłakowski

@Gothdo Kabul Ediyorum. Birisi bilmiyorsa function will return the object, rather than an arraybir hata alabilir, ancak bunun kullanıcılara bağlı olduğunu düşünüyorum.
soytian

0

Başlayarak aggaton cevabı , bu aslında (ya da istediği elemanı döndüren bir işlevdir nullbulunamadı değilse), verilen arrayve bir callbackdöner "doğru" öğesi için bir truthy değeri o fonksiyonu:

function findElement(array, callback) {
    var elem;
    return array.some(function(e) {
        if (callback(e)) {
            elem = e;
            return true;
        }
    }) ? elem : null;
});

Unutmayın, bu desteklemediği için IE8'de yerel olarak çalışmaz some. Bir çoklu dolgu sağlanabilir, alternatif olarak her zaman klasik fordöngü vardır:

function findElement(array, callback) {
    for (var i = 0; i < array.length; i++)
        if (callback(array[i])) return array[i];
    return null;
});

Aslında daha hızlı ve daha kompakt. Ancak tekerleği yeniden icat etmek istemiyorsanız, alt çizgi veya lodash gibi bir yardımcı program kütüphanesi kullanmanızı öneririm.


0

En kısa,

var theAnswerObj = _.findWhere(array, {id : 42});

1
Bu altçizgi kütüphanesinin kullanılmasını gerektirir, OP düz bir javascript veya jQuery çözümü istedi
Tobias Beuving

2
alt çizgiyi eklediğinizde, bu kısa bir cevap değildir!
Tim Ogilvy

-1

"AxesOptions" öğesini, nesne formatı {: field_type => 2,: fields => [1,3,4]} olan bir nesne dizisi olarak düşünün

function getFieldOptions(axesOptions,choice){
  var fields=[]
  axesOptions.each(function(item){
    if(item.field_type == choice)
        fields= hashToArray(item.fields)
  });
  return fields;
}
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.