Как найти значение в массиве объектов в JavaScript?


91

У меня есть массив объектов:

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

Я хочу иметь возможность найти в объекте / массиве ключ «ужин» и посмотреть, соответствует ли он «суши».

Я знаю, что в jQuery есть $ .inArray, но он, похоже, не работает с массивами объектов. А может я ошибаюсь. indexOf также, похоже, работает только на одном уровне массива.

Для этого нет функции или существующего кода?


Об этом уже спрашивали. Вы должны написать свою собственную функцию или использовать другую библиотеку.
— Феликс Клинг,

1
Обратите внимание, что Objectв Javascript зарезервирован Objectобъект-объект, т.е. мать всех объектов.
— adamse 03

1
вопрос и принятый ответ не связаны с многомерными массивами, а больше с фильтрацией одномерного массива по значениям свойств его элементов. => Они не решили мою проблему «найти значение в многомерном массиве».
— Мартин Шнайдер

Ответы:


213

Если у вас есть такой массив, как

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

Вы можете использовать filterметод объекта Array:

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

В новых реализациях JavaScript вы можете использовать выражение функции:

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

Вы можете искать людей, "dinner": "sushi"использующихmap

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

или reduce

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

Я уверен, что вы сможете обобщить это на произвольные ключи и значения!


7
Просто имейте в виду, что эти решения являются частью ECMAScript 5 и не поддерживаются в IE8. kangax.github.com/es5-compat-table Насколько я предпочитаю ответ @adamse, Alex's более дружелюбен к "старому дерьмовому браузеру". Хотя не уверен в производительности.
— EasyCo

@SalmanA - ни вопрос, ни решение не относятся к jQuery. Используется javascript filter (), а не специфичный для jQuery $ .filter () - tutorialspoint.com/javascript/array_filter.htm
— Tapirboy

Как упоминалось EasyCo, функция фильтрации не поддерживается в IE8. Однако его легко добавить к прототипу Array и, следовательно, использовать в любом браузере с небольшой функцией в начале ваших скриптов. Это описано в документации фильтра . Он дает точную функцию, указанную в ECMA-262, так что это буквально одно и то же.
— dallin 08

1
Я только что добавил ответ, в котором используется grepметод jQuery . Возможно, имеет смысл включить ваш ответ, поскольку он такой же, как и то, что вы делаете, но зависит от jQuery и дружелюбен к браузеру.
— Zach Lysobey

Есть ли причина, по которой я продолжаю получать справочную ошибку с моей возвращаемой переменной? Я попробовал два верхних ответа, возвращающих «x», и он продолжает говорить, что он не определен ...
— Эван Лало

18

jQuery имеет встроенный метод, jQuery.grepкоторый работает аналогично filterфункции ES5 из ответа @ adamse и должен нормально работать в старых браузерах.

На примере Адамсе:

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

вы можете сделать следующее

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 .

Пока -1не будет действительным ключом.


почти поддержал это, но в посте не было объяснений.
— mickmackusa

10

Если вы собираетесь часто выполнять этот поиск, подумайте об изменении формата вашего объекта, чтобы ужин действительно был ключевым. Это похоже на назначение первичного кластерного ключа в таблице базы данных. Так, например:

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

Теперь вы можете легко получить к нему доступ следующим образом: Object['sushi']['name']

Или, если объект действительно такой простой (просто "имя" в объекте), вы можете просто изменить его на:

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

А затем получить доступ к нему , как: Object['sushi'].

Очевидно, что не всегда возможно или в ваших интересах реструктурировать ваш объект данных таким образом, но дело в том, что иногда лучший ответ - это подумать о том, структурирован ли ваш объект данных наилучшим образом. Создание такого ключа может быть быстрее и создавать более чистый код.


1
Обожаю ответ, но я обнаружил проблему с синтаксисом: мой работал только так: obj = {"pizza": {"name": "bob"}, "sushi": {"name": "john"}} alert ( obj ['пицца'] ['имя']); но все равно. Благодарность! нашел то, что искал! )
— aleXela 09

@alexela Спасибо, Алексела! Я обновил свой ответ вашим проницательным наблюдением! Я только что скопировал пример из сообщения OP и не стал добавлять кавычки, но вы правы - это не сработает, если не будут заключены хотя бы кавычки вокруг значений (при условии, что это значения, а не переменные).
— dallin

3

Найти объект в массиве можно с помощью библиотеки Alasql :

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

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

Попробуйте этот пример в jsFiddle .


3
Я не уверен, что это действительно заслуживает отрицательного голосования. Sql-подобные запросы к коллекциям становятся намного проще рассуждать и писать, когда требования становятся более сложными, чем один фильтр или вызов reduce. Alasql - довольно впечатляющая библиотека, но, по общему признанию, немного избыточна для приведенного выше примера.
— TomDotTom

1
если сам объект произошел из источника SQL, тогда это гениальный ответ.
— edwardsmarkf

1

Вы можете использовать простой цикл for:

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

В следующем примере скрипта все содержащиеся объекты помещаются dinner:sushiв массив:

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


1

Здесь уже есть много хороших ответов, так почему бы не еще один, используйте библиотеку, такую ​​как lodash или подчеркивание :)

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

Мне пришлось искать во вложенной структуре карты сайта первый элемент, который проходит по заданному пути. Я придумал следующий код, просто используя .map() .filter()и .reduce. Возвращает последний найденный элемент, соответствующий пути /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);

Редактировать 4n4904z07


0

Если вы хотите найти конкретный объект с помощью функции поиска, просто попробуйте что-то вроде этого:

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

Это пример объекта:

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

Код выполнит итерацию и найдет «пользовательский» массив и будет искать объект, который вы ищете внутри.

Моя проблема заключалась в том, что индекс массива менялся при каждом обновлении окна, и он был либо в третьем, либо во втором массиве, но это не имеет значения.

Работал как шарм для Меня!

В вашем примере это немного короче:

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

0

Я бы старался не изобретать велосипед. Мы используем сканирование объектов для всех наших потребностей в обработке данных. Концептуально это очень просто, но позволяет делать много интересных вещей. Вот как вы решите свой конкретный вопрос

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' }
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.