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

thu*_*gsb 1435 javascript arrays jquery object javascript-objects

我有一个数组:

myArray = [{'id':'73','foo':'bar'},{'id':'45','foo':'bar'}, etc.]
Run Code Online (Sandbox Code Playgroud)

我无法改变数组的结构.我正在传递id 45,我想'bar'在数组中获取该对象.

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

Guf*_*ffa 1453

由于您已经在使用jQuery,因此可以使用用于搜索数组的grep函数:

var result = $.grep(myArray, function(e){ return e.id == id; });
Run Code Online (Sandbox Code Playgroud)

结果是一个包含找到的项目的数组.如果您知道对象始终存在并且只出现一次,您可以使用它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
}
Run Code Online (Sandbox Code Playgroud)

  • 使用`===`而不是`==`会更安全,以避免JavaScript的`==`运算符出现奇怪的问题. (121认同)
  • 基本上我总是使用`===`因为它在其他编程语言中像_ ==`一样工作_exactly_.我认为`==`在JavaScript中不存在. (99认同)
  • 好吧,如果你绝对确定'e.id`和`id`都是字符串,我想可以使用`==`.但是如果你不确定,你可能会遇到问题(因为`''== 0`是'true`但是'''=== 0`是'false`).更不用说`===`似乎更快(http://stackoverflow.com/questions/359494/javascript-vs-does-it-matter-which-equal-operator-i-use#comment14900957_359494). (38认同)
  • @VickyChijwani:将字符串与字符串进行比较时是否有任何问题? (11认同)
  • @de.这里的许多答案提供了查找唯一值时的预期行为; 你可以通过它们提前返回或从循环中断(或指示较低级别的构造停止迭代)来识别它们.请参阅JaredPar对规范示例的回答,以及Aaronius对该答案的评论.通常,人们以这种方式区分"过滤"和"查找"功能,但术语各不相同.虽然效率更高,但这仍然是线性搜索,因此如果您想使用哈希表,请参阅Aaron Digulla的答案(谨防细节). (6认同)
  • @MatíasFidemraizer:这个答案不会尝试列出所有可能的解决方案,它只显示问题中指定的最简单和最兼容的解决方案.当有一个简单且支持它的解决方案时,IE 8仍然太过普遍,无法提倡不支持它的解决方案. (3认同)
  • @Guffa:事实上,对于这个问题,你的回答是完全正确的 - 我只是想指出它,因为这可能会让许多读者感到担心,否则他们可能会错过机会做正确的事情. (当搜索属性包含唯一值时). (2认同)

Mic*_*ski 957

使用find()方法:

myArray.find(x => x.id === '45').foo;
Run Code Online (Sandbox Code Playgroud)

来自MDN:

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


如果要查找其索引,请使用findIndex():

myArray.findIndex(x => x.id === '45');
Run Code Online (Sandbox Code Playgroud)

来自MDN:

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


如果要获取匹配元素的数组,请改用该filter()方法:

myArray.filter(x => x.id === '45');
Run Code Online (Sandbox Code Playgroud)

这将返回一个对象数组.如果要获取一组foo属性,可以使用以下map()方法执行此操作:

myArray.filter(x => x.id === '45').map(x => x.foo);
Run Code Online (Sandbox Code Playgroud)

附注:类似的方法find()filter()箭头的功能不被旧的浏览器(如IE)的支持,所以如果你想支持这些浏览器,你应该使用transpile代码巴贝尔(用填充工具).

  • 因此,对于多个测试条件,它会类似于: myArray.find(x => x.id === '45' && x.color == 'red').foo (4认同)
  • myArray.find(x => x.id === '45').foo; 如果没有 id 为“45”的对象,则抛出异常。 (4认同)
  • 对我来说,到目前为止最好的答案.不需要jQuery也不需要创建新的辅助数组. (2认同)
  • 我可以在“find”方法中添加多个条件吗? (2认同)

Aar*_*lla 356

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

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

... now you can use lookup[id]...
Run Code Online (Sandbox Code Playgroud)

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

这将不需要更多的内存,因为ID和对象将被共享.

  • @irJvV:不,这根本没有意义.如果您需要执行许多查找,上面的代码很有用.如果你只看一次,那么创建一个`lookup`对象是浪费时间. (7认同)
  • 正是我在寻找什么.有趣的是我试图通过每次尝试循环来过度复杂化,从我发现它时删除列表中的每个项目,当我只需要改变从CouchDB接收的数据并将其转换为对我有用的格式需要.+1先生! (6认同)
  • 这很聪明.我无法想象其他人如何通过查看每个用途的阵列来说服他人. (5认同)
  • 只要您不依赖于属性的顺序:http://stackoverflow.com/questions/4886314/chrome-and-probably-opera-sort-object-properties-automatically (4认同)

Rún*_*erg 168

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);
Run Code Online (Sandbox Code Playgroud)

它没有外部库.但是,如果您需要较旧的浏览器支持,则可能需要包含此polyfill.

  • 这可以简化为`myArray.find(d => d.id === 45).foo;`. (2认同)
  • @Shaggy 甚至`myArray.find(({ id }) =&gt; id === 45).foo`。但这是在 ES2015 语法得到支持之前编写的旧答案。@Gothdo 的 [answer](http://stackoverflow.com/a/35398031/2444959) 目前是线程中最新的。 (2认同)

Gij*_*anB 140

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

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

  • 对于记录,Lo-Dash(通常比Underscore更高性能)具有类似的方法.文档:http://lodash.com/docs#find (42认同)

pim*_*vdb 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
Run Code Online (Sandbox Code Playgroud)


Jar*_*Par 67

请尝试以下方法

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;
}
Run Code Online (Sandbox Code Playgroud)

  • 这不值得回答,但在现代浏览器中,这个解决方案可以写成:http://jsfiddle.net/rwaldron/j3vST/ (17认同)
  • 如果你想提高效率,请注意这个例子可能比使用filter()更快(参见Rick的例子),因为一旦找到第一个匹配的项目就返回,而filter()继续在完整的数组中运行,即使找到了比赛.这个也没有为每个项目创建额外数组或调用函数的成本. (12认同)
  • @Rick,关于这个答案最有趣的事情显然是你可以将firebug控制台添加到jsFiddle的输出窗口中.这比记录并告诉其他人打开控制台以查看输出要好得多.真棒! (3认同)
  • 由于到目前为止还没有人提到过,我想补充一点,AngularJS 还有一个 [filter](https://docs.angularjs.org/api/ng/filter/filter) 方法。 (2认同)

Dan*_*sso 43

myArray.filter(function(a){ return a.id == some_id_you_want })[0]
Run Code Online (Sandbox Code Playgroud)


wil*_*ell 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');
Run Code Online (Sandbox Code Playgroud)


Kam*_*ski 24

表现

今天 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)慢
  • 令人惊讶的是,基于Map(K) 的Firefox 小阵列解决方案比传统for(E)慢

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

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

在此处输入图片说明

搜索对象不存在时的结论

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

在此处输入图片说明

细节

对于解决方案

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

我进行了四项测试。在测试中,我想在 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));
Run Code Online (Sandbox Code Playgroud)
<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
Run Code Online (Sandbox Code Playgroud)

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

在此处输入图片说明


hun*_*ter 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";
Run Code Online (Sandbox Code Playgroud)

工作示例:http://jsfiddle.net/hunter/Pxaua/


Joe*_*wis 13

你可以使用过滤器,

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

get_my_obj = getById(73, myArray);
Run Code Online (Sandbox Code Playgroud)

  • @TobiasBeuving - 使用 Array.find() 的也是普通的 JS,应该在第一次查找时停止,这样会更有效。 (2认同)

Tom*_*Tom 11

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

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

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

var lookup = items.reduce((o,i)=>o[i.id]=o,{});
Run Code Online (Sandbox Code Playgroud)

然后,您可以在固定时间内获取物品,如下所示:

var bar = o[id];
Run Code Online (Sandbox Code Playgroud)

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


lag*_*lex 10

使用原生 Array.reduce

var array = [ {'id':'73' ,'foo':'bar'} , {'id':'45' ,'foo':'bar'} , ];
var id = 73;
Run Code Online (Sandbox Code Playgroud)
var found = array.reduce(function(a, b){
    return (a.id==id && a) || (b.id == id && b)
});
Run Code Online (Sandbox Code Playgroud)

如果找到则返回object元素,否则返回 false


mah*_*are 8

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

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

代码:

var items = mydata.filter(function(item){
    return item.word.toLowerCase().startsWith( 'gk );
})
Run Code Online (Sandbox Code Playgroud)

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

从 20k 个字符串中提取


agg*_*ton 7

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

var bFound = myArray.some(function (obj) {
    return obj.id === 45;
});
Run Code Online (Sandbox Code Playgroud)

  • 几乎。`bFound` 只是一个布尔值,如果一个元素满足所需的条件,它就是 `true`。 (2认同)

Zir*_*rak 6

迭代数组中的任何项目。对于您访问的每个项目,请检查该项目的 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
}
Run Code Online (Sandbox Code Playgroud)

同样的事情使用 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];
}
Run Code Online (Sandbox Code Playgroud)


dee*_*ame 6

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

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

array.find( {id: 75} );
Run Code Online (Sandbox Code Playgroud)

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

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

  • 嗯,这是邪恶的,因为新的 EcmaScript 版本可能会引入同名的新方法。猜猜看,这就是 [`find` 发生的事情](http://people.mozilla.org/~jorendorff/es6-draft.html#sec-array.prototype.find)。我的建议是,如果您想扩展原生原型,请始终使用更具体的名称,将最简单的名称留给未来的标准开发。 (2认同)

Dan*_*n W 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'
Run Code Online (Sandbox Code Playgroud)


Jon*_*lms 6

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

const map = new Map( myArray.map(el => [el.id, el]) );
Run Code Online (Sandbox Code Playgroud)

然后,您可以简单地执行以下操作:

map.get(27).foo
Run Code Online (Sandbox Code Playgroud)


小智 6

我们可以使用 Jquery 方法 $.each()/$.grep()

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

或者

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

使用 ES6 语法:

Array.find, Array.filter, Array.forEach, Array.map
Run Code Online (Sandbox Code Playgroud)

或者使用 Lodash https://lodash.com/docs/4.17.10#filter,下划线https://underscorejs.org/#filter


Nic*_*ons 6

正如其他人指出的那样,.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"
*/
Run Code Online (Sandbox Code Playgroud)

这可以通过.find()在使用 using 之前检查结果是否已定义来.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
Run Code Online (Sandbox Code Playgroud)


ste*_*iel 5

基于公认的答案:

jQuery:

var foo = $.grep(myArray, function(e){ return e.id === foo_id})
myArray.pop(foo)
Run Code Online (Sandbox Code Playgroud)

或 CoffeeScript:

foo = $.grep myArray, (e) -> e.id == foo_id
myArray.pop foo
Run Code Online (Sandbox Code Playgroud)


Sum*_*hal 5

使用Array.prototype.filter()功能。

演示https : //jsfiddle.net/sumiridhal/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
  }
 }
];
Run Code Online (Sandbox Code Playgroud)

筛选

var getPerson = function(name){
    return jsonObj.filter(function(obj) {
      return obj.name === name;
    });
}
Run Code Online (Sandbox Code Playgroud)


小智 5

更通用,更简短

function findFromArray(array,key,value) {
        return array.filter(function (element) {
            return element[key] == value;
        }).shift();
}
Run Code Online (Sandbox Code Playgroud)

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