¿Cómo encontrar un valor en una matriz de objetos en JavaScript?

91

Tengo una variedad de objetos:

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

Quiero poder buscar el objeto / matriz donde la clave es "cena" y ver si coincide con "sushi".

Sé que jQuery tiene $ .inArray, pero no parece funcionar en matrices de objetos. O tal vez me equivoque. indexOf también parece funcionar solo en un nivel de matriz.

¿No existe ninguna función o código para esto?

Preguntador
fuente
Esto se ha preguntado antes. Tienes que escribir tu propia función o usar alguna otra biblioteca.
Felix Kling
1
Tenga en cuenta que Objectestá reservado en Javascript, Objectes el objeto objeto, es decir, la madre de todos los objetos.
Adamse
1
La pregunta y la respuesta aceptada no están relacionadas con matrices multidimensionales sino más bien con el filtrado de matrices unidimensionales por los valores de propiedad de sus elementos. => No resolvieron mi problema "encontrar un valor en una matriz multidimensional".
Martin Schneider

Respuestas:

213

Si tiene una matriz como

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

Puede utilizar el filtermétodo de un objeto Array:

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

En implementaciones de JavaScript más recientes, puede usar una expresión de función:

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

Puede buscar personas que hayan "dinner": "sushi"utilizado unmap

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

o un reduce

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

¡Estoy seguro de que puede generalizar esto a claves y valores arbitrarios!

Adamse
fuente
7
Solo tenga en cuenta que estas soluciones son parte de ECMAScript 5 y no son compatibles con IE8. kangax.github.com/es5-compat-table Por mucho que prefiera la respuesta de @ adamse, la de alex es más amigable con los "viejos navegadores de mierda". Sin embargo, no estoy seguro del rendimiento.
EasyCo
@SalmanA - ni la pregunta o la solución se refiere a jQuery. Se usa el filtro javascript (), no $ .filter () específico de jQuery - tutorialspoint.com/javascript/array_filter.htm
Tapirboy
Como lo menciona EasyCo, la función de filtro no es compatible con IE8. Sin embargo, se agrega fácilmente al prototipo de Array y, por lo tanto, se puede usar en cualquier navegador con una pequeña función al comienzo de sus scripts. Esto se describe en la documentación del filtro . Proporciona la función exacta especificada en ECMA-262, por lo que es literalmente lo mismo.
dallin
1
Acabo de agregar una respuesta que usa el grepmétodo de jQuery . Podría tener sentido incluir su respuesta, ya que es el mismo concepto que lo que está haciendo, pero depende de jQuery y es compatible con el navegador de mierda.
Zach Lysobey
¿Hay alguna razón por la que sigo recibiendo un error de referencia con mi variable de retorno? Probé las dos respuestas principales que devolvieron "x" y sigue diciendo que no está definido ...
Evan Lalo
18

jQuery tiene un método incorporado jQuery.grepque funciona de manera similar a la filterfunción ES5 de la Respuesta de @ adamse y debería funcionar bien en navegadores más antiguos.

Usando el ejemplo de Adamse:

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

puedes hacer lo siguiente

jQuery.grep(peoples, function (person) { return person.dinner == "sushi" });
  // => [{ "name": "john", "dinner": "sushi" }]
Zach Lysobey
fuente
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 .

Siempre que -1nunca sea una clave válida.

alex
fuente
casi votó a favor de este, pero no hubo explicación en la publicación.
mickmackusa
10

Si va a realizar esta búsqueda con frecuencia, considere cambiar el formato de su objeto para que la cena sea la clave. Esto es como asignar una clave agrupada primaria en una tabla de base de datos. Así por ejemplo:

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

Ahora puede acceder fácilmente a él de esta manera: Object['sushi']['name']

O si el objeto realmente es así de simple (solo 'nombre' en el objeto), puede cambiarlo a:

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

Y luego acceder a ella como: Object['sushi'].

Obviamente, no siempre es posible o ventajoso reestructurar su objeto de datos de esta manera, pero el punto es que, a veces, la mejor respuesta es considerar si su objeto de datos está estructurado de la mejor manera. Crear una clave como esta puede ser más rápido y crear un código más limpio.

dallin
fuente
1
Amo tu respuesta, pero encontré un problema con la sintaxis: el mío solo funcionaba así: obj = {"pizza": {"name": "bob"}, "sushi": {"name": "john"}} alerta ( obj ['pizza'] ['nombre']); pero aún. ¡Gracias! encontré lo que estaba buscando! )
aleXela
@alexela ¡Gracias alexela! ¡Actualicé mi respuesta con su astuta observación! Acababa de copiar el ejemplo en la publicación del OP y me olvidé de agregar las comillas, pero tiene razón: no funcionará a menos que haya comillas al menos alrededor de los valores (asumiendo que son valores y no variables).
dallin
3

Puede encontrar el objeto en una matriz con la biblioteca Alasql :

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

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

Pruebe este ejemplo en jsFiddle .

agershun
fuente
3
No estoy seguro de que esto realmente mereciera ser rechazado. Las consultas similares a SQL sobre colecciones se vuelven mucho más fáciles de razonar y escribir cuando los requisitos se vuelven más complicados que un solo filtro o reducción de llamadas. Alasql es una biblioteca bastante impresionante, pero es cierto que es un poco exagerada para el ejemplo anterior.
TomDotTom
1
si el objeto en sí se originó a partir de una fuente SQL, entonces esta respuesta es pura genialidad.
edwardsmarkf
1

Puede usar un bucle for in simple:

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

El siguiente ejemplo de violín coloca todos los objetos que contienen dinner:sushien una matriz:

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

Rotareti
fuente
1

Ya hay muchas buenas respuestas aquí, así que ¿por qué no una más? Usa una biblioteca como lodash o subrayado :)

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

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

Tuve que buscar una estructura de mapa de sitio anidada para el primer elemento de hoja que mapea una ruta determinada. Se me ocurrió el siguiente código simplemente usando .map() .filter()y .reduce. Devuelve el último elemento encontrado que coincide con la ruta /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);

Editar 4n4904z07

Bagazo
fuente
0

Si desea encontrar un objeto específico a través de la función de búsqueda, intente algo como esto:

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

Este es un objeto de ejemplo:

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

El código iterará y encontrará la matriz "usuario" y buscará el objeto que busca en su interior.

Mi problema fue cuando el índice de la matriz cambiaba cada actualización de la ventana y estaba en la tercera o segunda matriz, pero no importa.

¡Funcionó como un encanto para mí!

En tu ejemplo es un poco más corto:

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');
z3r0
fuente
0

Intentaría no reinventar la rueda. Utilizamos el escaneo de objetos para todas nuestras necesidades de procesamiento de datos. Es conceptualmente muy simple, pero permite muchas cosas interesantes. Así es como resolvería su pregunta específica

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

const findDinner = (dinner, data) => objectScan(['*'], {
  abort: true,
  rtn: 'value',
  filterFn: ({ value }) => value.dinner === dinner
})(data);

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

console.log(findDinner('sushi', data));
// => { name: 'john', dinner: 'sushi' }
Vincent
fuente