Trova oggetto per ID in una matrice di oggetti JavaScript


1547

Ho un array:

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

Non riesco a cambiare la struttura dell'array. Mi viene passato un ID di 45e voglio ottenere 'bar'quell'oggetto nella matrice.

Come posso fare questo in JavaScript o usando jQuery?

Risposte:


1193

Usa il find()metodo:

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

Da MDN :

Il find()metodo restituisce il primo valore nella matrice, se un elemento nella matrice soddisfa la funzione di test fornita. Altrimenti undefinedviene restituito.


Se invece vuoi trovare il suo indice , usa findIndex():

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

Da MDN :

Il findIndex()metodo restituisce l'indice del primo elemento dell'array che soddisfa la funzione di test fornita. Altrimenti viene restituito -1.


Se si desidera ottenere una matrice di elementi corrispondenti, utilizzare filter()invece il metodo:

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

Ciò restituirà una matrice di oggetti. Se vuoi ottenere una matrice di fooproprietà, puoi farlo con il map()metodo:

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

Nota a margine: metodi come find()o filter()e le funzioni freccia non sono supportati dai browser più vecchi (come IE), quindi se si desidera supportare questi browser, è necessario transpilare il codice usando Babel (con il polyfill ).


2
Per più condizioni di test sarebbe quindi qualcosa di simile a: myArray.find (x => x.id === '45' && x.color == 'red'). Foo
Apqu

2
Per me, la migliore risposta finora. Non richiede jQuery né la creazione di nuove matrici ausiliarie.
Canta,

myArray.find (x => x.id === '45') non funziona su Mac PC
Govinda Rajbhar,

@TJCrowder Non credo sia una buona idea copiare e incollare i polyfill da MDN nel tuo codice; invece, dovresti usare i pacchetti npm con polyfill. E Babel include polyfill per le funzionalità ES2015 +, nel pacchetto babel-polyfill .
Michał Perłakowski il

2
myArray.find (x => x.id === '45'). foo; genera un'eccezione se non ci sono oggetti con ID "45".
Frazer Kirkman,

1466

Dato che stai già utilizzando jQuery, puoi utilizzare la funzione grep che è destinata alla ricerca di un array:

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

Il risultato è un array con gli elementi trovati. Se sai che l'oggetto è sempre lì e che si verifica solo una volta, puoi semplicemente usare result[0].fooper ottenere il valore. Altrimenti è necessario verificare la lunghezza dell'array risultante. Esempio:

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
Sarebbe più sicuro usare ===invece di ==, per evitare strani problemi con l' ==operatore JavaScript .
Vicky Chijwani,

11
@VickyChijwani: ci sono problemi nel confrontare una stringa con una stringa?
Guffa,

38
Bene, se sei assolutamente sicuro che entrambi e.ide idsaranno stringhe, suppongo che sia ok da usare ==. Ma se non sei sicuro, potresti dover affrontare problemi (poiché '' == 0è truema '' === 0è false). Per non parlare ===sembra essere più veloce ( stackoverflow.com/questions/359494/… ).
Vicky Chijwani,

101
Fondamentalmente lo uso sempre ===perché funziona esattamente come ==in altri linguaggi di programmazione. Considero ==inesistente in JavaScript.
Vicky Chijwani,

6
@de. Molte risposte qui forniscono il comportamento previsto quando si cercano valori univoci; essenzialmente puoi riconoscerli dal fatto che ritornano o si rompono presto dal loro ciclo (o istruisci un costrutto di livello inferiore per fermare l'iterazione). Vedi la risposta di JaredPar per un esempio canonico e il commento di Aaronius su quella risposta per la stessa intuizione. In generale, le persone distinguono tra le funzioni "filtro" e "trova" in questo modo, ma la terminologia varia. Sebbene sia più efficiente, questa è ancora una ricerca lineare, quindi se vuoi usare una tabella hash, vedi la risposta di Aaron Digulla (attenzione ai dettagli dell'impl.).
TNE

362

Un'altra soluzione è quella di creare un oggetto di ricerca:

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

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

Questo è particolarmente interessante se devi fare molte ricerche.

Ciò non richiederà molta più memoria poiché gli ID e gli oggetti saranno condivisi.


6
Esattamente quello che stavo cercando. Divertente come stavo provando a complicare eccessivamente cercando di scorrere ogni volta, rimuovendo ogni elemento dall'elenco come l'ho trovato quando avevo solo bisogno di mutare i dati ricevuti da CouchDB e farlo in un formato che è utile per il mio esigenze. +1 signore!
slickplaid

5
questo è intelligente. Non riesco a immaginare come gli altri siano stati convinti guardando tutto l'array per ogni uso.
Aladdin Mhemed,

4
Finché non si basano su ordine di proprietà: stackoverflow.com/questions/4886314/...
Marle1

Sta usando una pausa; nel loop una buona opzione / miglioramento se sai che c'è solo un oggetto da trovare?
irJvV,

7
@irJvV: No, non ha affatto senso. Il codice sopra è utile se devi fare molte ricerche. Se guardi solo una volta, la creazione di un lookupoggetto è una perdita di tempo.
Aaron Digulla,

174

ECMAScript 2015 fornisce il metodo find () sugli array:

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

Funziona senza librerie esterne. Ma se desideri un supporto per browser meno recente , potresti voler includere questo polyfill .


1
Probabilmente perché sembra ancora molto sperimentale e non molti browser lo supportano, developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
lejonl

2
Questo può essere semplificato myArray.find(d=>d.id===45).foo;.
Shaggy

1
@Shaggy o addirittura myArray.find(({ id }) => id === 45).foo. Ma questa è una vecchia risposta che è stata scritta prima che la sintassi ES2015 fosse supportata come adesso. La risposta di @ Gothdo è attualmente la più aggiornata nel thread.
Rúnar Berg,

1
@Shaggy se .find () restituisce un valore indefinito, l'ottimizzazione genera un errore. Quindi questa soluzione può essere utilizzata solo nei casi in cui è garantita una corrispondenza.
Herbert Peters,

1
@HerbertPeters Se si vuole essere sicuri di poter sempre puntuale null-controllo, che sarà davvero facile con concatenamento optional : myArray.find(d => d.id === 45)?.foo.
Rúnar Berg,

141

Underscore.js ha un buon metodo per questo:

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

42
Per la cronaca, Lo-Dash (che è spesso più performante di Underscore) ha un metodo simile. Documenti qui: lodash.com/docs#find
user456584,

Se ti aspetti un solo oggetto, l'utilizzo di findWhere sarebbe più efficiente poiché dopo aver trovato un risultato, la ricerca non andrebbe oltre.
sempre il

@Foreever Dai documenti di _.find: "La funzione ritorna non appena trova un elemento accettabile e non attraversa l'intero elenco."
GijsjanB,

129

Penso che il modo più semplice sarebbe il seguente, ma non funzionerà su Internet Explorer 8 (o precedente):

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

Sono curioso, c'è qualche vantaggio prestazionale qui rispetto al solito for?
Igor Zinov'yev,

@Igor Zinov'yev: Sì, certamente ci sono impatti sulle prestazioni con quegli strumenti array ES5. Viene eseguita una funzione separata per ogni elemento, quindi non sarà molto veloce rispetto a un forloop diretto .
pimvdb,

Quindi stai dicendo che sarebbe più lento? Inoltre, scansionerà sempre l'intero array, per quanto posso vedere, mentre il forciclo terminerà alla prima corrispondenza.
Igor Zinov'yev,

Se hai bisogno di supporto per IE8, inseriscilo in: stackoverflow.com/questions/7153470/…
Adam Grant,

Questo codice genererà un errore se non ci sono elementiid
Stan,

71

Prova quanto segue

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
Questa non era degna della sua stessa risposta, ma nei browser moderni questa soluzione può essere scritta come: jsfiddle.net/rwaldron/j3vST
Rick

12
Se stai cercando efficienza, nota che questo esempio è probabilmente più veloce dell'uso di filter () (vedi l'esempio di Rick) poiché questo ritorna quando trova il primo elemento corrispondente mentre filter () continua a funzionare attraverso l'intero array anche dopo aver trovato un incontro. Anche questo non ha il costo di creare un array aggiuntivo o chiamare una funzione per ogni elemento.
Aaronio

3
@Rick, la cosa più interessante di quella risposta è apparentemente che puoi aggiungere la console firebug alla finestra di output in jsFiddle. È molto meglio che accedere e dire a qualcun altro di aprire la console per vedere l'output. Eccezionale!
KyleMit,

1
Dato che nessuno lo ha menzionato finora, volevo aggiungere che AngularJS ha anche un metodo di filtro .
Eno,



31

Una versione generica e più flessibile della funzione findById sopra:

// 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

Puoi ottenerlo facilmente usando la funzione 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";

Esempio di lavoro: http://jsfiddle.net/hunter/Pxaua/


1
Ho dimenticato il fatto che jQuery maprimuove automaticamente gli nullelementi. Sembra fuorviante per me e per il concetto comune di map, poiché il risultato non è della stessa lunghezza della collezione originale.
MaxArt

14

Puoi usare i filtri,

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

get_my_obj = getById(73, myArray);

1
@TobiasBeuving - Anche quello che usa Array.find () è semplicemente JS e dovrebbe fermarsi alla prima scoperta, quindi sarà più efficiente.
Adrian Lynch,

12

Sebbene ci siano molte risposte corrette qui, molte di esse non affrontano il fatto che si tratta di un'operazione inutilmente costosa se eseguita più di una volta. In un caso estremo questo potrebbe essere la causa di reali problemi di prestazioni.

Nel mondo reale, se stai elaborando molti elementi e le prestazioni sono una preoccupazione è molto più veloce inizialmente costruire una ricerca:

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

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

puoi quindi ottenere gli articoli a tempo fisso come questo:

var bar = o[id];

Puoi anche considerare di utilizzare una mappa anziché un oggetto come ricerca: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Map


11

Usando nativo 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)
});

restituisce l'elemento object se trovato, altrimenti false


Solo una nota, Array.reduce non è supportato in IE8 e precedenti.
Burn_E99

7

Se lo fai più volte, puoi impostare una mappa (ES6):

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

Quindi puoi semplicemente fare:

map.get(27).foo

6

Ecco come lo farei in puro JavaScript, nel modo più minimale che riesco a pensare che funzioni in ECMAScript 3 o versioni successive. Ritorna non appena viene trovata una corrispondenza.

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

Più generico e breve

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

nel tuo caso es. var element = findFromArray(myArray,'id',45)che ti darà l'intero elemento.


4

Puoi provare Sugarjs da http://sugarjs.com/ .

Ha un metodo molto dolce su Array, .find. Quindi puoi trovare un elemento come questo:

array.find( {id: 75} );

È inoltre possibile passare un oggetto con più proprietà ad esso per aggiungere un'altra "clausola where".

Nota che Sugarjs estende gli oggetti nativi e alcune persone lo considerano molto malvagio ...


2
Bene, è malvagio, poiché può accadere che nuove versioni di EcmaScript possano introdurre nuovi metodi con lo stesso nome. E indovina un po ', è esattamente quello che è successofind . Il mio suggerimento è che se si desidera estendere i prototipi nativi, utilizzare sempre nomi più specifici, lasciando i più semplici agli sviluppi standard futuri.
MaxArt

questo commento ha quasi 2 anni e oggi preferirei usare lodash comunque. Tuttavia, se lo desideri, puoi leggere questo argomento sul sito Web sugarjs. A loro avviso prendono una buona posizione: sugarjs.com/native
deepflame

1
L'operazione ha richiesto specificamente una soluzione javascript o jquery
Tobias Beuving,

4

Sulla base della risposta accettata:

jQuery:

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

O CoffeeScript:

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

4

Di recente, devo affrontare la stessa cosa in cui devo cercare la stringa da un array enorme.

Dopo alcune ricerche ho scoperto che sarà facile da gestire con un semplice codice:

Codice:

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

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

Serach da 20k stringhe


3

Scorrere su qualsiasi elemento dell'array. Per ogni oggetto che visiti, controlla l'ID dell'articolo. Se è una partita, restituiscila.

Se vuoi solo il codez:

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
}

E la stessa cosa usando i metodi Array di 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];
}

3

Finché il browser supporta ECMA-262 , 5a edizione (dicembre 2009), questo dovrebbe funzionare, quasi una riga:

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

2
Quasi. bFoundè solo un valore booleano truese un elemento soddisfa la condizione richiesta.
MaxArt

3

Puoi farlo anche in puro JavaScript usando la funzione "filtro" incorporata per gli array:

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

Quindi ora passa semplicemente "id" al posto di keye "45" al posto di value, e otterrai l'intero oggetto che corrisponde a un id di 45. Quindi sarebbe,

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

16
Non modificare oggetti che non possiedi.
Michał Perłakowski,

3

Usa la Array.prototype.filter()funzione.

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

FILTRO

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

come posso cercare all'interno di un oggetto nidificato? Come animali domestici = falso dovrebbe restituire due oggetti.
Valay,

usa il .filtermetodo on obj.infonel ciclo nidificato. var getPerson = function(name){ return jsonObj.filter(function(obj) { return obj.info.filter(function(info) { return pets === false; }); }); }
Sumit Ridhal,

potresti usare lo stile es6 troppo imo ... const filterData = jsonObj.filter (obj => obj.name === 'Alex')
DagicCross


2

Mi è piaciuta molto la risposta fornita da Aaron Digulla, ma avevo bisogno di mantenere la mia gamma di oggetti in modo da poterla scorrere più tardi. Quindi l'ho modificato in

	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


Utilizzata la stessa soluzione più veloce per la ricerca di elementi nell'array. Ma qui l'analisi è ridondante.
Ale,

1

Uso:

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

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

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

Dovrebbe restituire un oggetto per ID.


potresti abbreviare il tuo codice usando return obj.id === 5? obj: false; Uso $ .each molto per iterare su array.
marcel

@marcel: non funzionerà. Dato che restituire false finirà il ciclo, troverebbe l'oggetto solo se fosse il primo elemento dell'array.
Guffa,

1

Questa soluzione può essere utile anche:

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

L'ho fatto proprio come $.grepe se un oggetto viene scoperto, la funzione restituirà l'oggetto, piuttosto che un array.


2
Non modificare oggetti che non possiedi.
Michał Perłakowski,

@ Accordo. Se qualcuno non lo sapesse function will return the object, rather than an arraypotrebbe avere un errore, ma penso che dipenda dagli utenti.
soytian,

0

A partire dalla risposta di aggaton , questa è una funzione che restituisce effettivamente l'elemento desiderato (o nullse non trovato), data la arraye una callbackfunzione che restituisce un valore di verità per l'elemento "corretto":

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

Ricorda solo che questo non funziona nativamente su IE8-, in quanto non supporta some. È possibile fornire un polyfill, in alternativa c'è sempre il classico forloop:

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

In realtà è più veloce e più compatto. Ma se non vuoi reinventare la ruota, ti suggerisco di usare una libreria di utilità come underscore o lodash.


0

Più breve,

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

1
Ciò richiede l'uso della libreria di sottolineatura, l'OP ha richiesto una semplice soluzione javascript o jQuery
Tobias Beuving,

2
una volta incluso il trattino basso, questa non è una risposta breve!
Tim Ogilvy,

-1

Considera "axesOptions" come una matrice di oggetti con un formato oggetto {: 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;
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.