Як знайти значення в масиві об'єктів у 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.03.11

1
питання та прийнята відповідь не пов'язані з багатовимірними масивами, а більше з одновимірною фільтрацією масиву за значеннями властивостей його елементів. => Вони не вирішили мою проблему "пошук значення у багатовимірному масиві".
Мартін Шнайдер

Відповіді:


212

Якщо у вас є масив, такий як

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]

або a 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, алекс є більш дружнім до "старого сраного браузера". Не впевнений у продуктивності.
EasyCo

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

Як згадано у EasyCo, функція фільтра не підтримується в IE8. Однак його легко додати до прототипу Array і таким чином використовувати в будь-якому браузері з невеликою функцією на початку ваших сценаріїв. Це описано в документації до фільтра . Він дає точну функцію, зазначену в ECMA-262, тож це буквально одне і те ж.
Даллін,

1
Я щойно додав відповідь, яка використовує grepметод jQuery . Можливо, має сенс включити свою відповідь як таку саму концепцію, що і те, що ви робите, але залежну від jQuery та підручну для браузера.
Зак Лисобей,

Чи є причина, через яку я постійно отримую посилання на помилку зі своєю змінною повернення? Я спробував дві найкращі відповіді, повертаючи "x", і він постійно каже, що це невизначено ...
Еван Лало,

18

jQuery має вбудований метод, jQuery.grepякий працює подібно до функції ES5 filterз відповіді @ adamse, і повинен чудово працювати у старих браузерах.

На прикладі 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

@alexela Дякую alexela! Я оновив свою відповідь вашим проникливим спостереженням! Я щойно скопіював приклад у дописі OP та нехтував додаванням лапок, але ти маєш рацію - це не спрацює, якщо навколо значень не існують лапки хоча б за умови, що це значення, а не змінні.
Даллін,

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, до колекцій стають набагато простішими для обдумування та написання, коли вимоги ускладнюються, ніж одиничний фільтр або зменшення виклику. Alasql - це досить вражаюча бібліотека, але, правда, трохи надмірне для наведеного вище прикладу.
TomDotTom

1
якщо сам об'єкт походить із джерела SQL, то ця відповідь є чистим генієм.
edwardsmarkf

1

Ви можете використовувати простий цикл 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]);
    }
}

Наступний приклад скрипки містить усі об’єкти, що містяться, 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"}
}

Код повторить і знайде масив "користувач" і буде шукати об'єкт, який ви шукаєте всередині.

Моя проблема полягала в тому, що індекс масиву змінював кожне оновлення вікна, і це було або в 3-му, або в другому масиві, але це не має значення.

Працював для мене як оберіг!

У Вашому прикладі він трохи коротший:

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.