Come trovare un valore in una matrice di oggetti in JavaScript?


90

Ho una serie di oggetti:

Object = {
   1 : { name : bob , dinner : pizza },
   2 : { name : john , dinner : sushi },
   3 : { name : larry, dinner : hummus }
}

Voglio essere in grado di cercare l'oggetto / array dove la chiave è "cena" e vedere se corrisponde a "sushi".

So che jQuery ha $ .inArray, ma non sembra funzionare su array di oggetti. O forse mi sbaglio. indexOf sembra anche funzionare solo su un livello di array.

Non esiste una funzione o un codice esistente per questo?


Questo è stato chiesto prima. Devi scrivere la tua funzione o usare qualche altra libreria.
Felix Kling

1
Si prega di notare che Objectè riservato in Javascript, Objectè l'oggetto object, cioè la madre di tutti gli oggetti.
adamse

1
la domanda e la risposta accettata non sono correlate agli array multidimensionali ma più al filtraggio di array unidimensionali in base ai valori delle proprietà dei suoi elementi. => Non hanno risolto il mio problema "trovare un valore in un array multidimensionale".
Martin Schneider,

Risposte:


211

Se hai un array come

var people = [
  { "name": "bob", "dinner": "pizza" },
  { "name": "john", "dinner": "sushi" },
  { "name": "larry", "dinner": "hummus" }
];

Puoi usare il filtermetodo di un oggetto Array:

people.filter(function (person) { return person.dinner == "sushi" });
  // => [{ "name": "john", "dinner": "sushi" }]

Nelle implementazioni JavaScript più recenti puoi utilizzare un'espressione di funzione:

people.filter(p => p.dinner == "sushi")
  // => [{ "name": "john", "dinner": "sushi" }]

Puoi cercare persone che "dinner": "sushi"usano un filemap

people.map(function (person) {
  if (person.dinner == "sushi") {
    return person
  } else {
    return null
  }
}); // => [null, { "name": "john", "dinner": "sushi" }, null]

o a reduce

people.reduce(function (sushiPeople, person) {
  if (person.dinner == "sushi") {
    return sushiPeople.concat(person);
  } else {
    return sushiPeople
  }
}, []); // => [{ "name": "john", "dinner": "sushi" }]

Sono sicuro che sei in grado di generalizzare questo a chiavi e valori arbitrari!


7
Tieni presente che queste soluzioni fanno parte di ECMAScript 5 e non sono supportate in IE8. kangax.github.com/es5-compat-table Per quanto io preferisca la risposta di @ adamse, quella di alex è più "vecchio browser di merda" amichevole. Non sono sicuro delle prestazioni però.
EasyCo

@SalmanA - né la domanda o la soluzione si riferisce a jQuery. Viene utilizzato il filtro javascript (), non $ .filter () specifico per jQuery - tutorialspoint.com/javascript/array_filter.htm
Tapirboy

Come accennato da EasyCo, la funzione di filtro non è supportata in IE8. Tuttavia, è facilmente aggiunto al prototipo Array e quindi utilizzabile in qualsiasi browser con una piccola funzione all'inizio degli script. Ciò è descritto nella documentazione del filtro . Fornisce la funzione esatta specificata in ECMA-262, quindi è letteralmente la stessa cosa.
dallin

1
Ho appena aggiunto una risposta che utilizza il grepmetodo di jQuery . Potrebbe avere senso inserire la tua risposta in quanto è lo stesso concetto di quello che stai facendo, ma dipendente da jQuery e compatibile con i browser di merda.
Zach Lysobey

C'è un motivo per cui continuo a ricevere un errore di riferimento con la mia variabile di ritorno? Ho provato le prime due risposte restituendo "x" e continua a dire che non è definito ...
Evan Lalo

18

jQuery ha un metodo integrato jQuery.grepche funziona in modo simile alla filterfunzione ES5 dalla risposta di @ adamse e dovrebbe funzionare bene sui browser meno recenti.

Usando l'esempio di adamse:

var peoples = [
  { "name": "bob", "dinner": "pizza" },
  { "name": "john", "dinner": "sushi" },
  { "name": "larry", "dinner": "hummus" }
];

puoi fare quanto segue

jQuery.grep(peoples, function (person) { return person.dinner == "sushi" });
  // => [{ "name": "john", "dinner": "sushi" }]

10
var getKeyByDinner = function(obj, dinner) {
    var returnKey = -1;

    $.each(obj, function(key, info) {
        if (info.dinner == dinner) {
           returnKey = key;
           return false; 
        };   
    });

    return returnKey;       

}

jsFiddle .

Finché -1non è mai una chiave valida.


ho quasi votato in alto, ma nel post non c'erano spiegazioni.
mickmackusa

10

Se farai spesso questa ricerca, valuta la possibilità di cambiare il formato del tuo oggetto in modo che la cena sia effettivamente una chiave. È un po 'come assegnare una chiave cluster primaria in una tabella di database. Quindi, ad esempio:

Obj = { 'pizza' : { 'name' : 'bob' }, 'sushi' : { 'name' : 'john' } }

Ora puoi accedervi facilmente in questo modo: Object['sushi']['name']

Oppure, se l'oggetto è davvero così semplice (solo 'nome' nell'oggetto), potresti semplicemente cambiarlo in:

Obj = { 'pizza' : 'bob', 'sushi' : 'john' }

E poi accedervi come: Object['sushi'].

Ovviamente non è sempre possibile oa tuo vantaggio ristrutturare il tuo oggetto dati in questo modo, ma il punto è che a volte la risposta migliore è considerare se il tuo oggetto dati è strutturato nel modo migliore. Creare una chiave come questa può essere più veloce e creare un codice più pulito.


1
Ti piacerebbe rispondere, ma ho trovato un problema con la sintassi: il mio ha funzionato solo così: obj = {"pizza": {"name": "bob"}, "sushi": {"name": "john"}} alert ( obj ["pizza"] ["nome"]); ma ancora. Grazie! trovato quello che stavo cercando! )
aleXela

@alexela Grazie alexela! Ho aggiornato la mia risposta con la tua astuta osservazione! Avevo appena copiato l'esempio nel post dell'OP e trascurato di aggiungere le virgolette, ma hai ragione: non funzionerà a meno che non ci siano virgolette almeno intorno ai valori (supponendo che siano valori e non variabili).
dallin

3

Puoi trovare l'oggetto nell'array con la libreria Alasql :

var data = [ { name : "bob" , dinner : "pizza" }, { name : "john" , dinner : "sushi" },
     { name : "larry", dinner : "hummus" } ];

var res = alasql('SELECT * FROM ? WHERE dinner="sushi"',[data]);

Prova questo esempio in jsFiddle .


3
Non sono sicuro che questo meritasse davvero di essere votato. Le query di tipo SQL sulle raccolte diventano molto più facili da ragionare e scrivere quando i requisiti diventano più complicati di un singolo filtro o di una chiamata ridotta. Alasql è una libreria piuttosto impressionante, ma certamente un po 'eccessiva per l'esempio sopra.
TomDotTom

1
se l'oggetto stesso ha avuto origine da un'origine SQL, questa risposta è pura genialità.
edwardsmarkf

1

Puoi usare un semplice ciclo for in:

for (prop in Obj){
    if (Obj[prop]['dinner'] === 'sushi'){

        // Do stuff with found object. E.g. put it into an array:
        arrFoo.push(Obj[prop]);
    }
}

Il seguente esempio di violino inserisce tutti gli oggetti che contengono dinner:sushiin un array:

https://jsfiddle.net/3asvkLn6/1/


1

Ci sono già molte buone risposte qui, quindi perché non un'altra, usa una libreria come lodash o underscore :)

obj = {
   1 : { name : 'bob' , dinner : 'pizza' },
   2 : { name : 'john' , dinner : 'sushi' },
   3 : { name : 'larry', dinner : 'hummus' }
}

_.where(obj, {dinner: 'pizza'})
>> [{"name":"bob","dinner":"pizza"}]

0

Ho dovuto cercare una struttura della mappa del sito nidificata per il primo elemento foglia che crea un determinato percorso. Ho creato il seguente codice usando solo .map() .filter()e .reduce. Restituisce l'ultimo elemento trovato che corrisponde al percorso /c.

var sitemap = {
  nodes: [
    {
      items: [{ path: "/a" }, { path: "/b" }]
    },
    {
      items: [{ path: "/c" }, { path: "/d" }]
    },
    {
      items: [{ path: "/c" }, { path: "/d" }]
    }
  ]
};

const item = sitemap.nodes
  .map(n => n.items.filter(i => i.path === "/c"))
  .reduce((last, now) => last.concat(now))
  .reduce((last, now) => now);

Modifica 4n4904z07


0

Cercherei di non reinventare la ruota. Usiamo la scansione degli oggetti per tutte le nostre esigenze di elaborazione dei dati. È concettualmente molto semplice, ma consente molte cose interessanti. Ecco come risolveresti la tua domanda specifica

Definizione dei dati

const data = {
   1 : { name : 'bob' , dinner : 'pizza' },
   2 : { name : 'john' , dinner : 'sushi' },
   3 : { name : 'larry', dinner : 'hummus' }
};

Logica

const objectScan = require('object-scan');

const scanner = (input) => {
  let obj = null;
  objectScan(['*.dinner'], {
    filterFn: (key, value, { parents }) => {
      if (value === 'sushi') {
        obj = parents[0];
      }
    },
    breakFn: () => obj !== null
  })(data);
  return obj;
};

const result = scanner(data);

Produzione

// => result
{
  "name": "john",
  "dinner": "sushi"
}

0

Se vuoi trovare un oggetto specifico tramite la funzione di ricerca, prova qualcosa del genere:

    function findArray(value){

        let countLayer = dataLayer.length;
        for(var x = 0 ; x < countLayer ; x++){

            if(dataLayer[x].user){
                let newArr = dataLayer[x].user;
                let data = newArr[value];
                return data;
            }

        }

        return null;

    }

    findArray("id");

Questo è un oggetto di esempio:

layerObj = {
    0: { gtm.start :1232542, event: "gtm.js"},
    1: { event: "gtm.dom", gtm.uniqueEventId: 52},
    2: { visitor id: "abcdef2345"},
    3: { user: { id: "29857239", verified: "Null", user_profile: "Personal", billing_subscription: "True", partners_user: "adobe"}
}

Il codice itererà e troverà l'array "utente" e cercherà l'oggetto che cerchi all'interno.

Il mio problema era quando l'indice dell'array cambiava ogni aggiornamento della finestra ed era nel terzo o nel secondo array, ma non importa.

Ha funzionato benissimo per me!

Nel tuo esempio è un po 'più breve:

function findArray(value){

    let countLayer = Object.length;
    for(var x = 0 ; x < countLayer ; x++){

        if(Object[x].dinner === value){
            return Object[x];
        }

    }

    return null;

}

findArray('sushi');
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.