Знайдіть об’єкт за ідентифікатором у масиві об’єктів JavaScript


1545

У мене масив:

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

Я не в змозі змінити структуру масиву. Мені передають ідентифікатор 45, і я хочу отримати 'bar'цей об’єкт у масиві.

Як це зробити в JavaScript або за допомогою jQuery?

Відповіді:


1186

Використовуйте find()метод:

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

Від MDN :

find()Метод повертає перше значення в масиві, якщо елемент в масиві задовольняє умовам функції. В іншому випадку undefinedповертається.


Якщо ви хочете знайти його індекс , скористайтеся findIndex():

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

Від MDN :

findIndex()Метод повертає індекс першого елемента в масиві , який задовольняє умову тестування функції. Інакше -1 повертається.


Якщо ви хочете отримати масив відповідних елементів, скористайтеся filter()методом:

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

Це поверне масив об’єктів. Якщо ви хочете отримати масив fooвластивостей, ви можете зробити це map()методом:

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

Побічна примітка: такі методи, як find()або filter(), і функції стрілок не підтримуються старими браузерами (наприклад, IE), тому, якщо ви хочете підтримувати ці браузери, вам слід перекласти код за допомогою Babel (за допомогою поліфауни ).


2
Тому для кількох умов тестування це буде щось на зразок: myArray.find (x => x.id === '45' && x.color == 'червоний') foo
Apqu

2
Для мене найкраща відповідь поки що. Не потрібен jQuery, ні створення нових допоміжних масивів.
Канта

myArray.find (x => x.id === '45') він не працює на mac PC
Govinda Rajbhar

@TJCrowder Я не думаю, що це гарна ідея копіювати і вставляти поліфіли з MDN у свій код; натомість слід використовувати npm-пакети з поліфайлами. А Babel включає поліфіли для функцій ES2015 + в пакет babel-polyfill .
Michał Perłakowski

2
myArray.find (x => x.id === '45'). foo; викидає виняток, якщо немає об’єкта з ідентифікатором "45".
Фрейзер Кіркман

1466

Оскільки ви вже використовуєте jQuery, ви можете використовувати функцію grep, яка призначена для пошуку масиву:

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

Результат - масив із знайденими елементами. Якщо ви знаєте, що об’єкт завжди є і що він виникає лише один раз, ви можете просто скористатися, result[0].fooщоб отримати значення. В іншому випадку слід перевірити довжину отриманого масиву. Приклад:

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
Було б безпечніше використовувати ===замість того ==, щоб уникнути дивні проблеми з в JavaScript ==оператора.
Vicky Chijwani

11
@VickyChijwani: Чи є проблеми при порівнянні рядка з рядком?
Гуффа

38
Ну, якщо ви абсолютно впевнені, що обидва e.idі idбудуть рядками, я вважаю, що це нормально використовувати ==. Але якщо ви не впевнені, у вас можуть виникнути проблеми (оскільки '' == 0є, trueале '' === 0є false). Не кажучи вже ===про те, що швидше ( stackoverflow.com/questions/359494/… ).
Vicky Chijwani

101
В основному я завжди використовую, ===оскільки він працює точно так само, як і ==в інших мовах програмування. Я вважаю, що ==в JavaScript не існує.
Vicky Chijwani

6
@de. Багато відповідей дають намічену поведінку під час пошуку унікальних цінностей; їх можна по суті розпізнати за тим, що вони рано повертаються або вириваються зі свого циклу (або доручають конструкції нижчого рівня припинити ітерацію). Дивіться відповідь ДжаредПара для канонічного прикладу та коментар Ааронія до цієї відповіді для тієї самої думки. Загалом, люди розрізняють між собою функції «фільтра» та «пошуку», але термінологія відрізняється. Хоча це і більш ефективно, це все-таки лінійний пошук, тому якщо ви хочете використовувати хеш-таблицю, дивіться відповідь Аарона Дігулла (остерігайтеся детальних відомостей).
тне

362

Іншим рішенням є створення об’єкта пошуку:

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

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

Це особливо цікаво, якщо вам потрібно зробити багато пошукових запитів.

Для цього не знадобиться значно більше пам’яті, оскільки ідентифікатори та об’єкти будуть спільними.


6
Саме те, що я шукав. Смішно, як я намагався надмірно ускладнювати це, намагаючись перебирати цикл кожен раз, видаляючи кожен елемент зі списку, як я виявив його, коли мені потрібно було лише мутувати отримані дані з CouchDB і отримувати їх у корисному для мене форматі потреби. +1 сер!
slickplaid

5
це розумно. Я не уявляю, як переконалися інші, переглядаючи всі масиви для кожного використання.
Аладдін Мхемед

4
До тих пір , поки ви не покладатися на порядок властивостей: stackoverflow.com/questions/4886314 / ...
Marle1

Використовує перерву; в циклі гарний варіант / покращення, якщо ви знаєте, що знайти лише один об’єкт?
irJvV

7
@irJvV: Ні, це зовсім не має сенсу. Код, описаний вище, корисний, якщо вам потрібно зробити багато пошукових запитів. Якщо ви дивитесь лише один раз, то створення lookupоб’єкта - це марна трата часу.
Аарон Дігулла

174

ECMAScript 2015 пропонує метод find () для масивів:

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

Він працює без зовнішніх бібліотек. Але якщо ви хочете підтримати старіший веб-переглядач, можливо, ви хочете включити цю полів .


1
Ймовірно, це все ще здається дуже експериментальним, і не багато браузерів підтримують його, developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
lejonl

2
Це можна спростити до myArray.find(d=>d.id===45).foo;.
Кудлатий

1
@Shaggy або навіть myArray.find(({ id }) => id === 45).foo. Але це стара відповідь, написана до того, як синтаксис ES2015 був так само підтримуваний, як і зараз. @ Gothdo в відповідь в даний час є найбільш актуальною в потоці.
Rúnar Berg

1
@Shaggy, якщо .find () повернеться невизначено, то ваша оптимізація видає помилку. Тому це рішення можна використовувати лише у випадках, коли відповідність гарантована.
Герберт Пітерс

1
@HerbertPeters Якщо ви хочете бути впевнений , що ви можете Alway нуль-чек, який буде дуже легко з опціональною ланцюжком : myArray.find(d => d.id === 45)?.foo.
Рунар Берг

141

Underscore.js має для цього хороший метод:

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

42
Для запису, Lo-Dash (який часто демонструється більш ефективно, ніж Underscore) має подібний метод. Документи тут: lodash.com/docs#find
user456584

Якщо ви очікуєте лише одного об’єкта, то використання findWhere було б більш ефективним, оскільки після пошуку одного результату пошук не продовжуватиметься.
Ніколи

@Foreever З документів _.find: "Функція повертається, як тільки знайде прийнятний елемент, і не проходить весь список."
GijsjanB

129

Я думаю, що найпростішим способом було б наступне, але він не працюватиме в Internet Explorer 8 (або раніше):

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

Мені цікаво, чи є тут якась перевага у виконанні порівняно зі звичайною for?
Ігор Зинов'єв

@ Ігор Зінов'єв: Так, із цими інструментами масивів ES5 безумовно є вплив на продуктивність. Для кожного елемента виконується окрема функція, тому вона не буде дійсно швидкою порівняно з прямим forциклом.
pimvdb

Так ти кажеш, що це буде повільніше? Крім того, він завжди сканує весь масив, наскільки я бачу, тоді як forцикл закінчується в першому збігу.
Ігор Зінов'єв

Якщо вам потрібна підтримка IE8, просто залиште це: stackoverflow.com/questions/7153470/…
Адам Грант

Цей код призведе до помилки, якщо з цим немає жодного елементаid
Стен

71

Спробуйте наступне

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
Це не було гідним власної відповіді, але в сучасних браузерах це рішення можна записати так: jsfiddle.net/rwaldron/j3vST
Рік

12
Якщо ви збираєтеся досягти ефективності, зауважте, що цей приклад, швидше за все, швидше, ніж використання filter () (див. Приклад Ріка), оскільки цей повертається, як тільки він знайде перший відповідний елемент, тоді як filter () продовжує працювати через повний масив навіть після знаходження сірник. Цей також не має витрат на створення додаткового масиву або виклик функції для кожного елемента.
Аароній

3
@ Rick, найцікавіше в цьому відповіді, мабуть, ви можете додати консоль firebug до вихідного вікна в jsFiddle. Це набагато краще, ніж вести реєстрацію та казати комусь іншому відкрити консоль, щоб побачити вихід. Дивовижно!
KyleMit

1
Оскільки ніхто досі не згадував про це, я хотів додати, що AngularJS також має метод фільтрування .
Eno



31

Узагальнена та більш гнучка версія функції findById вище:

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

Це легко отримати за допомогою функції 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";

Приклад роботи: http://jsfiddle.net/hunter/Pxaua/


1
Я забув про те, що jQuery mapавтоматично видаляє nullелементи. Мені це здається оманливим і для загальної концепції map, оскільки результат не має однакової довжини оригінальної колекції.
MaxArt

14

Ви можете використовувати фільтри,

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

get_my_obj = getById(73, myArray);

1
@TobiasBeuving - той, який використовує Array.find (), також є звичайним JS і повинен зупинитися на першій знахідці, тому буде більш ефективним.
Адріан Лінч

12

Хоча тут є багато правильних відповідей, багато з них не звертаються до факту, що це зайва дорога операція, якщо вона робиться більше одного разу. В крайньому випадку, це може стати причиною реальних проблем з роботою.

У реальному світі, якщо ви обробляєте багато предметів, продуктивність викликає занепокоєння, спочатку побудувати пошук:

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

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

Ви можете потрапити на товари у встановлений час так:

var bar = o[id];

Ви також можете використати Map замість об'єкта в якості пошуку: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Map


11

Використання рідного 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)
});

повертає об'єктний елемент, якщо його знайдено, в іншому випадку false


Лише зауважте, що Array.reduce не підтримується в IE8 та нижче.
Burn_E99

7

Якщо ви зробите це кілька разів, ви можете створити карту (ES6):

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

Тоді ви можете просто зробити:

map.get(27).foo

6

Ось як я б про це пішов у чистому JavaScript, я, як мінімум, думаю про те, що працює в ECMAScript 3 або пізнішій версії. Він повертається, як тільки знайдеться відповідність.

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

Більш родовий і короткий

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

у вашому випадку var element = findFromArray(myArray,'id',45)це дасть вам весь елемент.


4

Ви можете спробувати Sugarjs з http://sugarjs.com/ .

Вона має дуже солодкий метод на масивах, .find. Таким чином, ви можете знайти такий елемент:

array.find( {id: 75} );

Ви також можете передати об'єкт з більшістю властивостей до нього, щоб додати ще одне "де-пункт".

Зауважте, що Sugarjs розширює рідні об’єкти, і деякі люди вважають це дуже злим ...


2
Ну, це зло, так як це може статися так, що нові версії ECMAScript можуть ввести нові методи з тим же ім'ям. І вгадайте що, саме зfind цим і сталося . Моя пропозиція полягає в тому, що якщо ви хочете розширити власні прототипи, завжди використовуйте більш конкретні імена, залишаючи найпростіші для майбутніх стандартних розробок.
MaxArt

цьому коментарю майже 2 роки, і сьогодні я б скоріше скористався лодашем. Однак якщо ви хочете, можете прочитати цю тему на веб-сайті sugarjs. Вони добре ставляться до вашої думки: sugarjs.com/native
deepflame

1
Оператор спеціально попросив рішення javascript або jquery
Tobias Beuving

4

Спираючись на прийняту відповідь:

jQuery:

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

Або CoffeeScript:

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

4

Останнім часом мені доводиться стикатися з тим самим, у якому мені потрібно шукати рядок з величезного масиву.

Після деякого пошуку я знайшов, що легко впоратися з простим кодом:

Код:

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

Дивіться https://jsfiddle.net/maheshwaghmare/cfx3p40v/4/

Serach з 20k струн


3

Ітерація над будь-яким елементом масиву. Кожен предмет, який ви відвідуєте, перевірте його. Якщо це збіг, поверніть його.

Якщо ви просто хочете кодек:

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
}

І те саме, що використовує методи масиву 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

Поки веб-переглядач підтримує ECMA-262 , 5-е видання (грудень 2009 р.), Це повинно працювати майже майже з одного лайнера:

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

2
Майже. bFoundє просто булевим, тобто trueякщо елемент задовольняє необхідну умову.
MaxArt

3

Це можна зробити навіть у чистому JavaScript, використовуючи вбудовану функцію "фільтр" для масивів:

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

Тож тепер просто передайте "id" замість keyта "45" замість value, і ви отримаєте повний об'єкт, що відповідає ідентифікатору 45. Так це було б,

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

16
Не змінюйте об'єкти, якими ви не володієте.
Michał Perłakowski

3

Використовуйте Array.prototype.filter()функцію.

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

ФІЛЬТР

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

як я можу шукати вкладений об'єкт? Як і домашні тварини = false повинні повертати два об'єкти.
Валай

.filterметод використання obj.infoу вкладеному циклі. var getPerson = function(name){ return jsonObj.filter(function(obj) { return obj.info.filter(function(info) { return pets === false; }); }); }
Суміт Рідхал

ви можете використовувати стиль es6 занадто imo ... const filterData = jsonObj.filter (obj => obj.name === 'Alex')
DagicCross

3

Ми можемо використовувати методи Jquery $.each()/$.grep()

var data= [];
$.each(array,function(i){if(n !== 5 && i > 4){data.push(item)}}

або

var data = $.grep(array, function( n, i ) {
  return ( n !== 5 && i > 4 );
});

використовувати синтаксис ES6:

Array.find, Array.filter, Array.forEach, Array.map

Або скористайтеся Lodash https://lodash.com/docs/4.17.10#filter , Underscore https://underscorejs.org/#filter


2

Мені дуже сподобалася відповідь, яку надав Аарон Дігулла, але мені потрібно було зберегти масив об'єктів, щоб я міг переглядати її пізніше. Тому я змінив його на

	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


Використовується те саме рішення, що найшвидше для пошуку елементів у масиві. Але розбір тут зайвий.
алеха

1

Використання:

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

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

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

Він повинен повернути об’єкт за ідентифікатором.


ви можете скоротити свій код, використовуючи return obj.id === 5? obj: хибний; Я багато використовую $ .each для ітерації над масивами.
marcel

@marcel: Це не спрацює. Оскільки повернення false завершиться циклом, він знайде об'єкт лише в тому випадку, якщо це був перший елемент у масиві.
Гуффа

1

Це рішення також може бути корисним:

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

Я зробив це так само, $.grepі якщо один об'єкт виявиться, функція поверне об'єкт, а не масив.


2
Не змінюйте об'єкти, якими ви не володієте.
Michał Perłakowski

@Gothdo Я згоден. Якщо хтось не знав, function will return the object, rather than an arrayможе помилитися, але я думаю, це залежить від користувачів.
соїтян

0

Починаючи з відповіді aggaton , це функція, яка фактично повертає шуканий елемент (або nullякщо його не знайдено), з огляду на функцію arrayта callbackфункцію, яка повертає правильне значення для "правильного" елемента:

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

Пам'ятайте лише, що це не працює в IE8-, оскільки воно не підтримує some. Можна заповнити полів, або завжди є класичний forцикл:

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

Це насправді швидше і компактніше. Але якщо ви не хочете винаходити колесо, я пропоную використовувати бібліотеку утиліт, наприклад, підкреслення або позначення.


0

Найкоротший,

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

1
Для цього потрібне використання бібліотеки підкреслення, ОП попросило звичайне рішення JavaScript або jQuery
Tobias Beuving

2
як тільки ви включите підкреслення, це не коротка відповідь!
Тім Огілві

-1

Розглянемо "axesOptions" масивом об'єктів з форматом об'єкта {: field_type => 2,: polja => [1,3,4]}

function getFieldOptions(axesOptions,choice){
  var fields=[]
  axesOptions.each(function(item){
    if(item.field_type == choice)
        fields= hashToArray(item.fields)
  });
  return fields;
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.