Znajdź obiekt według identyfikatora w tablicy obiektów JavaScript

1545

Mam tablicę:

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

Nie jestem w stanie zmienić struktury tablicy. Przekazano mi identyfikator 45i chcę uzyskać 'bar'ten obiekt w tablicy.

Jak to zrobić w JavaScript lub przy użyciu jQuery?

bandyta
źródło

Odpowiedzi:

1186

Użyj find()metody:

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

Z MDN :

find()Sposób powraca do pierwszej wartości w tablicy, a element w tablicy spełnia podaną funkcję testowania. W przeciwnym razie undefinedjest zwracany.


Jeśli zamiast tego chcesz znaleźć jego indeks , użyj findIndex():

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

Z MDN :

findIndex()Metoda zwraca wskaźnik pierwszego elementu w tablicy, który spełnia podane funkcji testowych. W przeciwnym razie zwracane jest -1.


Jeśli chcesz uzyskać tablicę pasujących elementów, użyj filter()metody:

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

Zwróci to tablicę obiektów. Jeśli chcesz uzyskać tablicę foowłaściwości, możesz to zrobić za pomocą map()metody:

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

Uwaga dodatkowa: metody takie jak find()i filter()oraz funkcje strzałek nie są obsługiwane przez starsze przeglądarki (takie jak IE), więc jeśli chcesz obsługiwać te przeglądarki, powinieneś przetłumaczyć swój kod za pomocą Babel (z polifill ).

Michał Perłakowski
źródło
2
W przypadku wielu warunków testowych byłoby to więc coś takiego: myArray.find (x => x.id === '45' && x.color == 'red'). Foo
Apqu
2
Dla mnie najlepsza jak dotąd odpowiedź. Nie wymaga jQuery ani tworzenia nowych pomocniczych tablic.
Canta
myArray.find (x => x.id === '45') nie działa na komputerze Mac
Govinda Rajbhar
@TJCrowder Nie sądzę, że dobrym pomysłem jest kopiowanie i wklejanie wypełnień z MDN do swojego kodu; zamiast tego powinieneś używać pakietów npm z polifillami. A Babel zawiera wielopełniacze dla funkcji ES2015 + w pakiecie babel-polyfill .
Michał Perłakowski
2
myArray.find (x => x.id === '45'). foo; zgłasza wyjątek, jeśli nie ma obiektu o identyfikatorze „45”.
Frazer Kirkman
1466

Ponieważ już używasz jQuery, możesz użyć funkcji grep, która jest przeznaczona do przeszukiwania tablicy:

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

Wynikiem jest tablica ze znalezionymi elementami. Jeśli wiesz, że obiekt jest zawsze obecny i że występuje tylko raz, możesz użyć result[0].footej wartości, aby uzyskać wartość. W przeciwnym razie powinieneś sprawdzić długość wynikowej tablicy. Przykład:

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
}
Guffa
źródło
124
Byłoby bezpieczniej jest używać ===zamiast ==, aby uniknąć dziwne problemy z JavaScript w ==operatora.
Vicky Chijwani,
11
@VickyChijwani: Czy występują problemy przy porównywaniu łańcucha do łańcucha?
Guffa,
38
Cóż, jeśli jesteś absolutnie pewien, że zarówno e.idi idbędzie struny, przypuszczam, że jest ok do użytku ==. Ale jeśli nie jesteś pewien, możesz napotkać problemy (ponieważ '' == 0jest, trueale '' === 0jest false). Nie wspominając o tym, ===że wydaje się być szybszy ( stackoverflow.com/questions/359494/… ).
Vicky Chijwani,
101
Zasadniczo zawsze używam, ===ponieważ działa dokładnie tak , jak ==w innych językach programowania. Uważam, że ==JavaScript nie istnieje.
Vicky Chijwani,
6
@de. Wiele odpowiedzi tutaj zapewnia zamierzone zachowanie podczas wyszukiwania unikalnych wartości; możesz je zasadniczo rozpoznać po tym, że wcześniej wracają lub przerywają pętlę (lub instruują konstrukcję niższego poziomu, aby przestała się iterować). Zobacz odpowiedź JaredPara na kanoniczny przykład i komentarz Aaroniusa do tej odpowiedzi dla tego samego wglądu. Ogólnie ludzie rozróżniają funkcje „filtruj” i „znajdź” w ten sposób, ale terminologia jest różna. Choć jest to bardziej wydajne, wciąż jest to wyszukiwanie liniowe, więc jeśli chcesz użyć tabeli skrótów, zobacz odpowiedź Aarona Digulli (uważaj na szczegóły impl.).
tne
362

Innym rozwiązaniem jest utworzenie obiektu odnośnika:

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

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

Jest to szczególnie interesujące, jeśli musisz wykonać wiele wyszukiwań.

Nie będzie to wymagało więcej pamięci, ponieważ identyfikatory i obiekty będą udostępniane.

Aaron Digulla
źródło
6
Dokładnie tego szukałem. Zabawne, jak próbowałem to nadmiernie skomplikować, próbując za każdym razem zapętlać, usuwając każdy element z listy, tak jak go znalazłem, gdy potrzebowałem tylko zmutować otrzymane dane z CouchDB i uzyskać format, który jest przydatny dla mojego wymagania. +1 panie!
slickplaid,
5
to jest mądre. Nie mogę sobie wyobrazić, jak przekonali się inni, patrząc na tablicę dla każdego zastosowania.
Aladdin Mhemed
4
Tak długo, jak nie będziesz polegać na kolejności właściwości: stackoverflow.com/questions/4886314/…
Marle1
Używa przerwy; w pętli dobra opcja / ulepszenie, jeśli wiesz, że jest tylko jeden obiekt do znalezienia?
irJvV
7
@irJvV: Nie, to wcale nie ma sensu. Powyższy kod jest przydatny, jeśli musisz wykonać wiele wyszukiwań. Jeśli spojrzysz tylko raz, stworzenie lookupobiektu to strata czasu.
Aaron Digulla
174

ECMAScript 2015 zapewnia metodę find () tablic:

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

Działa bez bibliotek zewnętrznych. Ale jeśli chcesz obsługiwać starszą przeglądarkę, możesz dołączyć tę funkcję wypełniania .

Rúnar Berg
źródło
1
Prawdopodobnie dlatego, że wciąż wydaje się być bardzo eksperymentalny i niewiele przeglądarek obsługuje go, developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
lejonl
2
Można to uprościć myArray.find(d=>d.id===45).foo;.
Shaggy
1
@ Shaggy lub nawet myArray.find(({ id }) => id === 45).foo. Ale to stara odpowiedź, która została napisana, zanim składnia ES2015 była równie dobrze obsługiwana, jak teraz. @ Gothdo za odpowiedź jest obecnie najbardziej aktualne w wątku.
Rúnar Berg,
1
@Shaggy, jeśli .find () zwraca wartość niezdefiniowaną, wówczas twoja optymalizacja zgłasza błąd. Tak więc tego rozwiązania można użyć tylko w przypadkach, w których gwarantowane jest dopasowanie.
Herbert Peters,
1
@HerbertPeters Jeśli chcesz być pewien, że można sprecyzowane zerowej-check, który będzie naprawdę proste z opcjonalną łańcuchowych : myArray.find(d => d.id === 45)?.foo.
Rúnar Berg,
141

Underscore.js ma dobrą metodę:

myArray = [{'id':'73','foo':'bar'},{'id':'45','foo':'bar'},etc.]
obj = _.find(myArray, function(obj) { return obj.id == '45' })
GijsjanB
źródło
42
Dla przypomnienia, Lo-Dash (który często jest wyraźnie bardziej wydajny niż Underscore) ma podobną metodę. Dokumenty tutaj: lodash.com/docs#find
user456584
Jeśli oczekujesz tylko jednego obiektu, użycie findWhere byłoby bardziej wydajne, ponieważ po znalezieniu jednego wyniku wyszukiwanie nie posunąłoby się dalej.
Zawsze
@Foreever Z dokumentacji _.find: „Funkcja powraca, gdy tylko znajdzie akceptowalny element, i nie przechodzi przez całą listę”.
GijsjanB,
129

Myślę, że najprostszym sposobem byłoby, ale nie będzie działać w Internet Explorerze 8 (lub wcześniejszym):

var result = myArray.filter(function(v) {
    return v.id === '45'; // Filter out the appropriate one
})[0].foo; // Get result and access the foo property
pimvdb
źródło
Jestem ciekawy, czy jest tu jakaś przewaga wydajności w porównaniu do zwykłej for?
Igor Zinov'yev
@Igor Zinov'yev: Tak, te narzędzia macierzy ES5 z pewnością wpływają na wydajność. Dla każdego elementu wykonywana jest osobna funkcja, więc nie będzie tak naprawdę szybka w porównaniu z bezpośrednią forpętlą.
pimvdb
Więc mówisz, że byłoby wolniej? Ponadto, o ile widzę, zawsze skanuje całą tablicę, podczas gdy forpętla kończy się przy pierwszym dopasowaniu.
Igor Zinov'yev
Jeśli potrzebujesz pomocy dla IE8, po prostu upuść to: stackoverflow.com/questions/7153470/…
Adam Grant
Ten kod zgłosi błąd, jeśli nie ma w tym elementuid
Stan
71

Spróbuj wykonać następujące czynności

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;
}
JaredPar
źródło
17
Nie było to warte własnej odpowiedzi, ale w nowoczesnych przeglądarkach to rozwiązanie można zapisać jako: jsfiddle.net/rwaldron/j3vST
Rick
12
Jeśli zależy Ci na wydajności, zauważ, że ten przykład jest prawdopodobnie szybszy niż użycie filter () (patrz przykład Ricka), ponieważ ten zwraca, gdy znajdzie pierwszy pasujący element, podczas gdy filter () kontynuuje działanie przez całą tablicę, nawet po znalezieniu mecz. Ten również nie kosztuje tworzenia dodatkowej tablicy ani wywoływania funkcji dla każdego elementu.
Aaronius
3
@Rick, najbardziej interesującą rzeczą w tej odpowiedzi jest najwyraźniej możesz dodać konsolę firebug do okna wyjściowego w jsFiddle. Jest to o wiele lepsze niż logowanie i mówienie komuś innemu, aby otworzył konsolę i zobaczył wyjście. Niesamowite!
KyleMit,
1
Ponieważ nikt do tej pory o tym nie wspominał, chciałem dodać, że AngularJS ma również metodę filtrowania .
Eno
31

Ogólna i bardziej elastyczna wersja powyższej funkcji findById:

// 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');
będzie Farrell
źródło
15

Możesz to łatwo uzyskać za pomocą funkcji map () :

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

Przykład roboczy: http://jsfiddle.net/hunter/Pxaua/

Łowca
źródło
1
Zapomniałem o tym, że jQuery mapautomatycznie usuwa nullelementy. Brzmi myląco dla mnie i dla wspólnej koncepcji map, ponieważ wynik nie ma takiej samej długości oryginalnej kolekcji.
MaxArt,
14

Możesz użyć filtrów,

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

get_my_obj = getById(73, myArray);
Joe Lewis
źródło
1
@TobiasBeuving - Ten, który używa Array.find (), jest również zwykłym JS i powinien zatrzymać się przy pierwszym znalezieniu, aby był bardziej wydajny.
Adrian Lynch,
12

Chociaż jest tutaj wiele poprawnych odpowiedzi, wiele z nich nie odnosi się do faktu, że jest to niepotrzebnie kosztowna operacja, jeśli jest wykonywana więcej niż jeden raz. W skrajnym przypadku może to być przyczyną rzeczywistych problemów z wydajnością.

W prawdziwym świecie, jeśli przetwarzasz wiele elementów, a problemem jest wydajność, znacznie szybciej jest początkowo zbudować wyszukiwanie:

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

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

następnie możesz dostać się na przedmioty w ustalonym czasie, takie jak to:

var bar = o[id];

Możesz również rozważyć użycie mapy zamiast obiektu jako odnośnika: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Map

Tomek
źródło
11

Używanie natywnego 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)
});

zwraca element obiektu, jeśli zostanie znaleziony, w przeciwnym razie false

laggingreflex
źródło
Uwaga: Array.reduce nie jest obsługiwany w IE8 i starszych wersjach.
Burn_E99
7

Jeśli zrobisz to wiele razy, możesz skonfigurować mapę (ES6):

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

Następnie możesz po prostu zrobić:

map.get(27).foo
Jonas Wilms
źródło
6

Oto jak poradzę sobie z tym w czystym JavaScript, w najbardziej minimalistyczny sposób, jaki mogę wymyślić, działa w ECMAScript 3 lub nowszym. Zwraca się, gdy tylko zostanie znalezione dopasowanie.

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'
Dan W.
źródło
5

Bardziej ogólny i krótki

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

w twoim przypadku np. var element = findFromArray(myArray,'id',45)to da ci cały element.

Savan Kaneriya
źródło
4

Możesz wypróbować Sugarjs ze strony http://sugarjs.com/ .

Ma bardzo słodki sposób na tablicach, .find. Możesz więc znaleźć element taki jak ten:

array.find( {id: 75} );

Możesz także przekazać obiekt o większej liczbie właściwości, aby dodać kolejną „klauzulę where”.

Zauważ, że Sugarjs rozszerza rodzime obiekty, a niektórzy uważają to za bardzo złe ...

deepflame
źródło
2
Dobrze, że jest zła, ponieważ może się zdarzyć, że nowe wersje ECMAScript może wprowadzić nowe metody o tej samej nazwie. I zgadnij co, dokładnie tak się stałofind . Moja sugestia jest taka, że ​​jeśli chcesz rozszerzyć prototypy natywne, zawsze używaj bardziej szczegółowych nazw, pozostawiając najprostsze dla przyszłych standardowych rozwiązań.
MaxArt,
ten komentarz ma prawie 2 lata i dzisiaj wolałbym mimo to skorzystać z lodash. Jeśli jednak chcesz, możesz przeczytać o tym temacie na stronie internetowej sugarjs. Uważają, że dobrze oceniają
deepflame
1
Operacja poprosiła konkretnie o javascript lub jquery
Tobias Beuving
4

Opierając się na przyjętej odpowiedzi:

jQuery:

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

Lub CoffeeScript:

foo = $.grep myArray, (e) -> e.id == foo_id
myArray.pop foo
Stevenspiel
źródło
4

Ostatnio muszę zmierzyć się z tym samym, w którym muszę przeszukać ciąg z ogromnej tablicy.

Po kilku poszukiwaniach znalazłem, że będzie to łatwe w obsłudze za pomocą prostego kodu:

Kod:

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

Zobacz https://jsfiddle.net/maheshwaghmare/cfx3p40v/4/

Serach z 20k strun

maheshwaghmare
źródło
3

Iteruj po dowolnym elemencie w tablicy. Dla każdego odwiedzanego elementu sprawdź jego identyfikator. Jeśli pasuje, zwróć go.

Jeśli chcesz tylko kod:

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
}

I to samo przy użyciu metod macierzy ECMAScript 5:

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];
}
Zirak
źródło
3

Tak długo, jak przeglądarka obsługuje ECMA-262 , piąta edycja (grudzień 2009 r.), Powinno to działać prawie w jednym wierszu:

var bFound = myArray.some(function (obj) {
    return obj.id === 45;
});
aggaton
źródło
2
Prawie. bFoundjest tylko wartością logiczną, która oznacza, trueże element spełnia wymagany warunek.
MaxArt
3

Możesz to zrobić nawet w czystym JavaScript, używając wbudowanej funkcji „filtrowania” tablic:

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

Teraz po prostu podaj „id” zamiast key„45” zamiast value, a otrzymasz pełny obiekt pasujący do identyfikatora 45. Tak więc,

myArr.filterObjects("id", "45");
kaizer1v
źródło
16
Nie modyfikuj obiektów, których nie posiadasz.
Michał Perłakowski
3

Użyj Array.prototype.filter()funkcji.

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

FILTR

var getPerson = function(name){
    return jsonObj.filter(function(obj) {
      return obj.name === name;
    });
}
Sumit Ridhal
źródło
jak mogę wyszukiwać w zagnieżdżonym obiekcie? Jak zwierzaki = fałsz powinien zwrócić dwa obiekty.
Valay
użyj .filtermetody obj.infow zagnieżdżonej pętli. var getPerson = function(name){ return jsonObj.filter(function(obj) { return obj.info.filter(function(info) { return pets === false; }); }); }
Sumit Ridhal
możesz użyć stylu es6 też zbyt imo ... const filterData = jsonObj.filter (obj => obj.name === 'Alex')
DagicCross
3

Możemy użyć metod Jquery $.each()/$.grep()

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

lub

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

użyj składni ES6:

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

Lub użyj Lodash https://lodash.com/docs/4.17.10#filter , Underscore https://underscorejs.org/#filter

TLbiz
źródło
2

Naprawdę podobała mi się odpowiedź udzielona przez Aarona Digullę, ale musiałem zachować mój zestaw obiektów, aby móc ją później iterować. Więc zmodyfikowałem to do

	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

quincyaft
źródło
Użyto tego samego rozwiązania jak najszybciej do znajdowania przedmiotów w tablicy Ale analiza jest tutaj zbędna.
aleha,
1

Posługiwać się:

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

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

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

Powinien zwrócić obiekt według identyfikatora.

volumexxx
źródło
możesz skrócić swój kod za pomocą return obj.id === 5? obj: false; Używam $ .each dużo do iteracji po tablicach.
marcel
@marcel: To nie zadziała. Ponieważ zwracanie wartości false zakończy pętlę, znajdzie obiekt tylko wtedy, gdy będzie to pierwszy element w tablicy.
Guffa,
1

To rozwiązanie może być również pomocne:

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

Zrobiłem to tak, $.grepa jeśli jeden obiekt zostanie znaleziony, funkcja zwróci obiekt, a nie tablicę.

soja
źródło
2
Nie modyfikuj obiektów, których nie posiadasz.
Michał Perłakowski
@Gothdo Zgadzam się. Jeśli ktoś nie wiedział, function will return the object, rather than an arraymoże popełnić błąd, ale myślę, że to zależy od użytkowników.
sojczyk
0

Zaczynając od odpowiedzi Agatona , jest to funkcja, która faktycznie zwraca poszukiwany element (lub nulljeśli nie został znaleziony), biorąc pod uwagę arrayoraz callbackfunkcję, która zwraca prawdziwą wartość dla „poprawnego” elementu:

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

Pamiętaj tylko, że to nie działa natywnie na IE8-, ponieważ nie obsługuje some. Można podać polifill, alternatywnie zawsze jest klasyczna forpętla:

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

Jest właściwie szybszy i bardziej kompaktowy. Ale jeśli nie chcesz wymyślać koła od nowa, sugeruję użycie biblioteki narzędziowej, takiej jak podkreślenie lub lodash.

MaxArt
źródło
0

Najkrótszy

var theAnswerObj = _.findWhere(array, {id : 42});
Manu
źródło
1
Wymaga to użycia biblioteki podkreślenia, OP poprosił o proste rozwiązanie w javascript lub jQuery
Tobias Beuving
2
po dodaniu podkreślenia nie jest to krótka odpowiedź!
Tim Ogilvy
-1

Rozważ „axesOptions” jako tablicę obiektów o formacie obiektu {: field_type => 2,: fields => [1,3,4]}

function getFieldOptions(axesOptions,choice){
  var fields=[]
  axesOptions.each(function(item){
    if(item.field_type == choice)
        fields= hashToArray(item.fields)
  });
  return fields;
}
ramya
źródło