Найти объект по идентификатору в массиве объектов JavaScript

1136

У меня есть массив:

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

Я не могу изменить структуру массива. Мне передается id 45, и я хочу получить 'bar' для этого объекта в массиве.

Как это сделать в JavaScript или с помощью jQuery?

Теги:
object
arrays
javascript-objects

31 ответ

595
Лучший ответ

Используйте метод 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полифоном).

  • 1
    Поэтому для нескольких условий тестирования это будет что-то вроде: myArray.find (x => x.id === '45' && x.color == 'red'). Foo
  • 2
    Для меня лучший ответ на данный момент. Не нуждается ни в jQuery, ни в создании новых вспомогательных массивов.
Показать ещё 5 комментариев
1357

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

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

В результате получается массив с найденными элементами. Если вы знаете, что объект всегда существует и что он встречается только один раз, вы можете просто использовать result[0].foo для получения значения. В противном случае вы должны проверить длину результирующего массива. Пример:

if (result.length == 0) {
  // not found
} else if (result.length == 1) {
  // access the foo property using result[0].foo
} else {
  // multiple items found
}
  • 113
    Было бы безопаснее использовать === вместо == , чтобы избежать странных проблем с оператором JavaScript == .
  • 11
    @VickyChijwani: Есть ли проблемы при сравнении строки со строкой?
Показать ещё 12 комментариев
363

Другим решением является создание объекта поиска:

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 сэр!
  • 5
    это умно Я не могу представить, как другие были убеждены, просматривая массив для каждого использования.
Показать ещё 11 комментариев
147

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

Работает без внешних библиотек. Но если вы хотите более старую поддержку браузера, вы можете включить this polyfill.

  • 1
    Вероятно, потому что это все еще кажется очень экспериментальным, и не многие браузеры поддерживают его, developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
  • 2
    Это можно упростить до myArray.find(d=>d.id===45).foo; ,
Показать ещё 5 комментариев
133

Underscore.js имеет хороший способ для этого:

myArray = [{'id':'73','foo':'bar'},{'id':'45','foo':'bar'},etc.]
obj = _.find(myArray, function(obj) { return obj.id == '45' })
  • 41
    Для записи, Lo-Dash (который часто демонстрирует большую производительность, чем Underscore) имеет аналогичный метод. Документы здесь: lodash.com/docs#find
  • 0
    Если вы ожидаете только один объект, то использование findWhere будет более эффективным, так как после поиска одного результата поиск не пойдет дальше.
Показать ещё 1 комментарий
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
  • 0
    Мне любопытно, есть ли здесь какое-то преимущество в производительности по сравнению с обычным for ?
  • 0
    @ Игорь Зиновьев: Да, с этими инструментами массива ES5, безусловно, сказывается производительность. Отдельная функция выполняется для каждого элемента, поэтому она не будет очень быстрой по сравнению с прямым циклом for .
Показать ещё 3 комментария
62

Попробуйте выполнить

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 комментария
44
myArray.filter(function(a){ return a.id == some_id_you_want })[0]
Показать ещё 1 комментарий
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');
14

Вы можете легко получить это с помощью функции 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
    Я забыл о том, что map jQuery автоматически удаляет null элементы. Это звучит вводящим в заблуждение для меня и для общей концепции map , поскольку в результате получается не та же самая длина оригинальной коллекции.
13

Вы можете использовать фильтры,

  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 и должен останавливаться при первом поиске, поэтому будет более эффективным.
10

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

В реальном мире, если вы обрабатываете множество элементов, а производительность - это гораздо быстрее, чем первоначально построить поиск:

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

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

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

var bar = o[id];

Вы также можете использовать карту вместо объекта в качестве поиска: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Map

10

Использование native 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

  • 0
    Просто обратите внимание, Array.reduce не поддерживается в IE8 и ниже.
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'
4

Если вы делаете это несколько раз, вы можете настроить карту (ES6):

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

Тогда вы можете просто сделать:

map.get(27).foo
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

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

Он имеет очень сладкий метод в массивах, .find. Итак, вы можете найти такой элемент:

array.find( {id: 75} );

Вы также можете передать объект с большим количеством свойств, чтобы добавить другое "where-clause".

Обратите внимание, что Sugarjs расширяет родные объекты, а некоторые люди считают это очень злым...

  • 1
    Ну, это зло, так как это может случиться так, что новые версии ECMAScript могут ввести новые методы с тем же именем. И угадайте что, это именно то, что случилось с find . Мое предложение состоит в том, что если вы хотите расширить собственные прототипы, всегда используйте более конкретные имена, оставляя самые простые из них для будущих стандартных разработок.
  • 0
    этому комментарию почти 2 года, и сегодня я все равно предпочел бы использовать lodash. Однако, если вы хотите, вы можете прочитать об этой теме на веб-сайте sugarjs. Они занимают хорошую позицию по вашему мнению: sugarjs.com/native
Показать ещё 1 комментарий
3

Вы можете сделать это даже в чистом JavaScript, используя встроенную функцию "filter" для массивов:

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

Итак, вместо "t22 > вместо" t22 "вместо" t21 "и" 45 "вы просто передадите" id ", и вы получите полный объект, соответствующий идентификатору 45. Таким образом, это будет

myArr.filterObjects("id", "45");
  • 15
    Не изменяйте объекты, которые вам не принадлежат.
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 Array:

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

Используйте функцию 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;
    });
}
  • 0
    как я могу искать внутри вложенного объекта? Как домашние животные = ложь должен вернуть два объекта.
  • 0
    использовать .filter метод на obj.info в вложенном цикле. var getPerson = function(name){ return jsonObj.filter(function(obj) { return obj.info.filter(function(info) { return pets === false; }); }); }
Показать ещё 1 комментарий
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
  • 0
    Используется то же решение, что и самое быстрое для поиска элементов в массиве. Но parseInt здесь избыточен.
2

Пока браузер поддерживает ECMA-262, 5-е издание (декабрь 2009 г.), это должно работать почти с одним слоем:

var bFound = myArray.some(function (obj) {
    return obj.id === 45;
});
  • 2
    Почти. bFound - это просто логическое значение, которое true если элемент удовлетворяет требуемому условию.
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
    Не изменяйте объекты, которые вам не принадлежат.
  • 0
    @ Да, я согласен. Если кто-то не знал, function will return the object, rather than an array может получить ошибку, но я думаю, что это зависит от пользователей.
1

Использование:

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

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

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

Он должен возвращать объект по id.

  • 0
    Вы могли бы сократить свой код, используя return obj.id === 5? obj: false; Я много использую $ .each для перебора массивов.
  • 0
    @ Marcel: Это не сработает. Так как возвращение false завершит цикл, он найдет объект, только если он был первым элементом в массиве.
0

Более общий и короткий

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

в вашем случае Ex. var element = findFromArray(myArray,'id',45), который даст вам весь элемент.

0

Мы можем использовать методы Jquery $.each()/$. Grep() var data= []; $.each(array,function(i){if(n !== 5 && я > 4){data.push(item)}} var data= []; $.each(array,function(i){if(n !== 5 && я > 4){data.push(item)}}

или же

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

использовать синтаксис ES6: Array.find, Array.filter, Array.forEach, Array.map

Или используйте Lodash https://lodash.com/docs/4.17.10#filter, Подчеркните https://underscorejs.org/#filter

0

Рассмотрим "axesOptions" как массив объектов с форматом объекта, являющимся {: field_type = > 2,: fields = > [1,3,4]}

function getFieldOptions(axesOptions,choice){
  var fields=[]
  axesOptions.each(function(item){
    if(item.field_type == choice)
        fields= hashToArray(item.fields)
  });
  return fields;
}
0

Кратчайший,

var theAnswerObj = _.findWhere(array, {id : 42});
  • 1
    Это требует использования библиотеки подчеркивания, OP попросил простое решение javascript или jQuery
  • 2
    как только вы добавите подчеркивание, это не короткий ответ!
0

Начиная с aggaton answer, это функция, которая фактически возвращает желаемый элемент (или null, если не найден), учитывая array и a callback, которая возвращает правдивое значение для "правильного" элемента:

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

Просто помните, что это не работает на IE8, поскольку оно не поддерживает some. A polyfill может быть предусмотрен, альтернативно всегда существует классический цикл for:

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

Это на самом деле быстрее и компактнее. Но если вы не хотите изобретать колесо, я предлагаю использовать библиотеку служебных программ, например, подчеркивание или lodash.

-3

Мой способ найти индекс массива:

index = myArray.map(getItemId).indexOf(id);
getItemId: function(item) {
  return item.id;
}

// to get foo property use index
myArray[index].foo

//If you want to use ES6
index = myArray.map((i) => i.id).indexOf(id)
myArray[index].foo
-5

Использовать метод фильтрации jQuery:

 $(myArray).filter(function()
 {
     return this.id == desiredId;
 }).first();

Это вернет первый элемент с указанным идентификатором.

Он также имеет приятный формат С# LINQ.

  • 4
    Метод filter предназначен для элементов, а не массивов. Вместо этого используйте метод grep .

Ещё вопросы

Сообщество Overcoder
Наверх
Меню