在JavaScript对象数组中按id查找对象

我有一个数组:

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

我无法更改数组的结构。我被传递了一个ID45,我想为数组中的该对象获取'bar'

我如何在JavaScript或使用jQuery中做到这一点?

2235333 次浏览

试试以下方法

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

我认为最简单的方法如下,但它不适用于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

遍历数组中的任何项目。对于您访问的每个项目,检查该项目的id。如果匹配,则返回它。

如果你只是想要代码:

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

您可以使用地图函数轻松获得:

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/

使用jQuery的filter方法:

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

这将返回具有指定Id的第一个元素。

它还具有漂亮的C#LINQ格式的好处。

另一种解决方案是创建一个查找对象:

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

如果您需要进行多次查找,这尤其有趣。

这不需要太多内存,因为ID和对象将被共享。

由于您已经在使用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}

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

您可以从http://sugarjs.com/尝试Sugarjs。

它在数组.find上有一个非常甜蜜的方法。所以你可以找到这样的元素:

array.find( {id: 75} );

您还可以将具有更多属性的对象传递给它以添加另一个“where子句”。

请注意,Sugarjs扩展了本机对象,有些人认为这是非常邪恶的。

Underscore.js有一个很好的方法:

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

用途:

var retObj ={};$.each(ArrayOfObjects, function (index, obj) {
if (obj.id === '5') { // id.toString() if it is int
retObj = obj;return false;}});return retObj;

它应该通过id返回一个对象。

你可以使用过滤器,

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

ECMAScript 2015(JavaScript ES6)提供查找数组上的方法:

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);
// printconsole.log(item.name);

它在没有外部库的情况下工作。但是如果你想要旧浏览器支持,你可能想要包含这种聚乙烯填料

只要浏览器支持ECMA-262,第5版(2009年12月),这应该可以工作,几乎是一行:

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

阿加顿的回答开始,这是一个实际返回所需元素的函数(如果未找到,则为null),给定arraycallback函数,该函数返回“正确”元素的truthy值:

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

请记住,这在IE8-上本机不起作用,因为它不支持some。可以提供一个Poly填充,或者总是有经典的for循环:

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

它实际上更快,更紧凑。但是如果你不想重新发明轮子,我建议使用像下划线或洛达什这样的实用程序库。

这个解决方案也可能有帮助:

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一样,如果找到一个对象,函数将返回该对象,而不是一个数组。

基于已接受的答案:

jQuery:

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

或CoffeeScript:

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

即使在纯JavaScript中,您也可以通过为数组使用内置的“filter”函数来做到这一点:

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

所以现在只需传递“id”代替key,传递“45”代替value,您将获得与id为45匹配的完整对象。所以这就是,

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

我真的很喜欢Aaron Digulla提供的答案,但需要保留我的对象数组,以便以后可以迭代它。所以我将其修改为

	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 usingarray[indexer[id]].property

最短的,

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

这是我在纯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 arrayreturn;}
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'

将“axesOptions”视为对象数组,对象格式为{:field_type=>2,:字段=>[1,3,4]}

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

使用原生#0

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

使用find()方法:

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

MDN

如果数组中的元素满足提供的测试函数,find()方法返回数组中的第一个值。否则返回undefined


如果你想找到它的索引,请使用findIndex()

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

MDN

findIndex()方法返回数组中满足提供的测试函数的第一个元素的索引。否则返回-1。


如果您想获取匹配元素的数组,请改用#0方法:

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

这将返回一个对象数组。如果您想获取foo属性的数组,您可以使用#1方法执行此操作:

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

旁注:旧浏览器(如IE)不支持find()filter()箭头函数等方法,因此如果您想支持这些浏览器,您应该使用巴别塔(使用聚填充)转换代码。

虽然这里有许多正确的答案,但其中许多都没有解决这样一个事实,即如果多次执行,这是一个不必要的昂贵操作。在极端情况下,这可能是真正性能问题的原因。

在现实世界中,如果您正在处理大量项目并且性能是一个问题,那么最初构建查找要快得多:

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

我找到数组索引的方法:

index = myArray.map((i) => i.id).indexOf(value_of_id);item = myArray[index];

使用Array.prototype.filter()函数。

DEMOhttps://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;});}

如果您多次这样做,您可以设置一个Map(ES6):

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

然后你可以简单地执行O(1)查找:

map.get(27).foo

我们可以使用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

或者使用Lodashhttps://lodash.com/docs/4.17.10#filter,Underscorehttps://underscorejs.org/#filter

更通用和简短

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

在您的情况下,Ex.var element = findFromArray(myArray,'id',45)将为您提供整个元素。

最近,我不得不面对同样的事情,我需要从一个巨大的数组中搜索字符串。

经过一些搜索,我发现使用简单的代码很容易处理:

代码:

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

https://jsfiddle.net/maheshwaghmare/cfx3p40v/4/

Serach from20k字符串

正如其他人所指出的,#0是在数组中查找一个对象的方法。但是,如果使用此方法找不到您的对象,您的程序将崩溃:

const myArray = [{'id':'73','foo':'bar'},{'id':'45','foo':'bar'}];const res = myArray.find(x => x.id === '100').foo; // Uh oh!/*Error:"Uncaught TypeError: Cannot read property 'foo' of undefined"or in newer chrome versions:Uncaught TypeError: Cannot read properties of undefined (reading 'foo')*/

这可以通过在使用.foo之前检查.find()的结果是否已定义来修复。现代JS允许我们使用可选链接轻松做到这一点,如果找不到对象则返回undefined,而不是使您的代码崩溃:

const myArray = [{'id':'73','foo':'bar'},{'id':'45','foo':'bar'}];const res = myArray.find(x => x.id === '100')?.foo; // No error!console.log(res); // undefined when the object cannot be found

动态缓存查找

在这个解决方案中,当我们搜索某个对象时,我们将其保存在缓存中。这是“始终搜索解决方案”和“在预计算中为每个对象创建哈希映射”之间的中间点。

let cachedFind = (()=>{let cache = new Map();return (arr,id,el=null) =>cache.get(id) || (el=arr.find(o=> o.id==id), cache.set(id,el), el);})();

// ---------// TEST// ---------
let myArray = [...Array(100000)].map((x,i)=> ({'id':`${i}`, 'foo':`bar_${i}`}));
// example usage
console.log( cachedFind(myArray,'1234').foo );




// Benchmark
let bench = (id) => {console.time   ('time for '+id );console.log    ( cachedFind(myArray,id).foo );  // FINDconsole.timeEnd('time for '+id );}
console.log('----- no cached -----');bench(50000);bench(79980);bench(99990);console.log('-----  cached   -----');bench(79980); // cachedbench(99990); // cached

性能

今天2020.06.20我在Chrome81.0,Firefox 77.0和Safari13.1上对所选解决方案进行测试。

使用预计算的解决方案的结论

具有预计算(K,L)的解决方案比其他解决方案(快得多),并且不会与它们进行比较-可能它们使用一些特殊的内置浏览器优化

  • 令人惊讶的是Chrome和Safari基于Map(K)的解决方案比基于对象{}(L)的解决方案快得多
  • 令人惊讶的是Safari基于对象{}(L)的小数组解决方案比传统的for(E)慢
  • 令人惊讶的是,基于Map(K)的Firefox小数组解决方案比传统的for(E)慢

当搜索对象始终存在时的结论

  • 使用传统for(E)的解决方案对于小数组最快,对于大数组更快
  • 使用缓存(J)的解决方案对于大数组来说是最快的-令人惊讶的是,对于小数组来说是中等速度
  • 基于find(A)和findIndex(B)的解决方案对于小阵列快速,对于大阵列中等快速
  • 基于$.map(H)的解决方案在小数组上最慢
  • 基于reduce(D)的解决方案在大数组上最慢

在此处输入图片描述

当搜索对象不存在时的结论

  • 基于传统for(E)的解决方案在小型和大型数组上最快(除了Chrome-小型数组,它的速度第二快)
  • 基于reduce(D)的解决方案在大数组上最慢
  • 使用缓存(J)的解决方案是中等速度,但如果我们将具有空值的键保存在缓存中,则可以加快速度(这里没有这样做,因为我们希望避免在缓存中无限的内存消耗,以防搜索许多不存在的键)

在此处输入图片描述

详情

对于解决方案

  • 没有预计算:ABCDEFGHIJ(J解决方案使用“内部”缓存,它的速度取决于搜索元素重复的频率)
  • 预计算KL

我执行了四个测试。在测试中,我想在10次循环迭代中找到5个对象(对象ID在迭代过程中不会改变)-所以我调用测试方法50次,但只有前5次有唯一的id值:

  • 小数组(10个元素)和搜索对象始终存在-您可以执行它这里
  • 大数组(10k元素)和搜索对象始终存在-您可以执行它这里
  • 小数组(10个元素)和搜索对象永远不存在-您可以执行它这里
  • 大数组(10k元素)和搜索对象永远不存在-您可以执行它这里

测试代码如下所示

function A(arr, id) {return arr.find(o=> o.id==id);}
function B(arr, id) {let idx= arr.findIndex(o=> o.id==id);return arr[idx];}
function C(arr, id) {return arr.filter(o=> o.id==id)[0];}
function D(arr, id) {return arr.reduce((a, b) => (a.id==id && a) || (b.id == id && b));}
function E(arr, id) {for (var i = 0; i < arr.length; i++) if (arr[i].id==id) return arr[i];return null;}
function F(arr, id) {var retObj ={};$.each(arr, (index, obj) => {if (obj.id == id) {retObj = obj;return false;}});return retObj;}
function G(arr, id) {return $.grep(arr, e=> e.id == id )[0];}
function H(arr, id) {return $.map(myArray, function(val) {return val.id == id ? val : null;})[0];}
function I(arr, id) {return _.find(arr, o => o.id==id);}
let J = (()=>{let cache = new Map();return function J(arr,id,el=null) {return cache.get(id) || (el=arr.find(o=> o.id==id), cache.set(id,el), el);}})();
function K(arr, id) {return mapK.get(id)}
function L(arr, id) {return mapL[id];}


// -------------// TEST// -------------
console.log('Find id=5');
myArray = [...Array(10)].map((x,i)=> ({'id':`${i}`, 'foo':`bar_${i}`}));const mapK = new Map( myArray.map(el => [el.id, el]) );const mapL = {}; myArray.forEach(el => mapL[el.id]=el);


[A,B,C,D,E,F,G,H,I,J,K,L].forEach(f=> console.log(`${f.name}: ${JSON.stringify(f(myArray, '5'))}`));
console.log('Whole array',JSON.stringify(myArray));
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min.js"></script>
This snippet only presents tested codes

示例测试搜索对象始终存在的小数组的Chrome结果

在此处输入图片描述

下面的代码将帮助您从嵌套对象中搜索数据中的值。

const updatedData = myArrayOfObjects.filter((obj: any) => Object.values(obj).some((val: any) => {if (typeof (val) == typeof ("str")) {return val.toString().includes(Search)} else {return Object.values(val).some((newval: any) => {if (newval !== null) {return newval.toString().includes(Search)}})}}))