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

时间:2011-09-09 15:42:29

标签: javascript jquery arrays object javascript-objects

我有一个阵列:

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

我无法更改数组的结构。我正在传递45的id,我希望在数组中获得'bar'该对象。

如何在JavaScript或使用jQuery中执行此操作?

35 个答案:

答案 0 :(得分:1437)

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

答案 1 :(得分:785)

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

附注:旧版浏览器(如IE)不支持find()filter()arrow functions等方法,因此如果您想支持这些浏览器,则应将其转换为代码使用Babel(使用polyfill)。

答案 2 :(得分:351)

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

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和对象将被共享。

答案 3 :(得分:162)

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

无需外部库即可运行。但是,如果您想要older browser support,则可能需要包含this polyfill

答案 4 :(得分:140)

Underscore.js有一个不错的方法:

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

答案 5 :(得分:125)

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

答案 6 :(得分:66)

尝试以下

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

答案 7 :(得分:42)

myArray.filter(function(a){ return a.id == some_id_you_want })[0]

答案 8 :(得分:30)

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

答案 9 :(得分: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/

答案 10 :(得分:13)

您可以使用过滤器,

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

get_my_obj = getById(73, myArray);

答案 11 :(得分:10)

性能

今天2020.06.20我针对选择的解决方案在Chrome 81.0,Firefox 77.0和Safari 13.1的MacOs High Sierra上进行了测试。

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

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

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

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

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

enter image description here

从不存在搜索对象的结论

  • 基于传统for(E)的解决方案在大型和大型阵列上速度最快(Chrome小型阵列除外,后者排名第二)
  • 基于reduce(D)的解决方案在大型阵列上最慢
  • 使用高速缓存(J)的解决方案速度中等,但是如果我们将具有空值的键保存在高速缓存中,则可以加快速度(此处未执行此操作,因为我们希望避免在高速缓存中没有很多空值时无限使用内存)现有密钥将被搜索)

enter image description here

详细信息

有关解决方案

  • 不进行预先计算:A B C D E F G H I J(J解决方案使用“内部”缓存,其速度取决于搜索元素重复的频率)
  • 具有预先计算 K L

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

  • 小数组(10个元素)和搜索到的对象始终存在-您可以HERE执行
  • 大数组(1万个元素)和搜索到的对象始终存在-您可以HERE执行
  • 小数组(10个元素)和搜索到的对象从不存在-您可以HERE执行
  • 大数组(10k个元素)和搜索到的对象从不存在-您可以HERE执行

经过测试的代码如下

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的结果是否始终存在搜索对象始终存在的小型阵列

enter image description here

答案 12 :(得分:10)

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

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

create proc spGetItemsByUser
@userName nvarchar(50)
as
begin
declare @userId int
declare @feedId table (id int)

select @userId = id 
from Users 
where name = @userName

insert into @feedid (id)
select feedid, isread 
from userstofeed 
where userid = @userId

select * from feed where id in (select id from @feedId)
select isread from userstofeed where userid = @userId //Here I'm getting bit if it read or not
end

然后你可以在固定时间内获得这样的物品:

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

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

您也可以考虑使用Map而不是对象作为查找:https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Map

答案 13 :(得分:10)

使用原生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)
});
如果找到,

返回object元素,否则返回false

答案 14 :(得分:6)

若您多次执行此操作,您可以设置地图(ES6):

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

然后你就可以做到:

map.get(27).foo

答案 15 :(得分: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'

答案 16 :(得分: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

答案 17 :(得分:4)

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

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

array.find( {id: 75} );

您还可以向其传递具有更多属性的对象,以添加另一个“where-clause”。

请注意,Sugarjs扩展了原生对象,有些人认为这非常邪恶......

答案 18 :(得分:3)

迭代数组中的任何项目。对于您访问的每件商品,请检查该商品的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];
}

答案 19 :(得分:3)

正如其他人指出的那样,.find()是在数组中查找一个对象时要走的路。但是,如果使用此方法找不到对象,则程序将崩溃:

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

可以通过在使用.find()之前检查是否定义.foo的结果来解决此问题。现代JS允许我们使用optional chaining轻松地做到这一点,如果找不到对象,则返回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

答案 20 :(得分: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;
    });
}

答案 21 :(得分:3)

即使在纯JavaScript中也可以使用内置的“过滤器”函数对数组执行此操作:

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

所以现在只需用“id”代替key和“45”来代替value,你就会得到匹配id为45的完整对象。那就是,< / p>

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

答案 22 :(得分:2)

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

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

答案 23 :(得分:2)

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

&#13;
&#13;
	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
&#13;
&#13;
&#13;

答案 24 :(得分:2)

更通用,更简短

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

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

答案 25 :(得分: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返回一个对象。

答案 26 :(得分: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一样,如果找到一个对象, function 将返回对象,而不是数组。

答案 27 :(得分:1)

动态缓存的查找

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

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 );  // FIND
  console.timeEnd('time for '+id );
}

console.log('----- no cached -----');
bench(50000);
bench(79980);
bench(99990);
console.log('-----  cached   -----');
bench(79980); // cached
bench(99990); // cached

答案 28 :(得分:0)

考虑&#34; axesOptions&#34;是一个对象格式为的对象数组 {:field_type =&gt; 2,:fields =&gt; [1,3,4]}

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

答案 29 :(得分:0)

最短,

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

答案 30 :(得分:0)

我们可以使用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,下划线https://underscorejs.org/#filter

答案 31 :(得分:0)

aggaton's answer开始,这是一个实际返回所需元素的函数(如果未找到,则返回null),给定arraycallback函数返回正确的&#34;正确的&#34;元素:

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

请记住,这并不适用于IE8-,因为它不支持some。可以提供polyfill,或者总是经典的for循环:

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

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

答案 32 :(得分:-1)

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

经过一番搜索,我发现使用简单的代码即可轻松处理

代码:

$item['images']->file_name ?? 'default_value';

请参见https://jsfiddle.net/maheshwaghmare/cfx3p40v/4/

Serach from 20k strings

答案 33 :(得分:-3)

我找到数组索引的方法:

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

var item = myArray[index];

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

答案 34 :(得分:-5)

使用jQuery的过滤方法:

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

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

它还具有良好的C#LINQ外观格式。