通过ID在JavaScript对象数组中查找对象


1544

我有一个数组:

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

我无法更改数组的结构。我正在传递ID为45,我想获取'bar'数组中的该对象。

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

Answers:


1185

使用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)的支持,所以如果你想支持这些浏览器,你应该使用transpile代码巴贝尔(用填充工具)。


2
因此,对于多个测试条件,它应该类似于:myArray.find(x => x.id ==='45'&& x.color =='red')。foo
Apqu

2
对我来说,到目前为止最好的答案。不需要jQuery也不创建新的辅助数组。
Canta

myArray.find(x => x.id ==='45')在Mac PC上不起作用
Govinda Rajbhar,

@TJCrowder我认为将MDN中的polyfill复制粘贴到您的代码中不是一个好主意。相反,您应该将npm软件包与polyfills一起使用。Babel确实在babel- polyfill套件中包含了ES2015 +功能的polyfill 。
米哈尔Perłakowski

2
myArray.find(x => x.id ==='45')。foo; 如果没有ID为“ 45”的对象,则引发异常。
Frazer Kirkman

1465

由于您已经在使用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:比较字符串与字符串是否有任何问题?
Guffa

38
好吧,如果您完全确定e.idid都将是字符串,那么我想可以使用==。但是,如果不确定,您可能会遇到问题(因为'' == 0是,true但是'' === 0false)。更不用说===似乎更快了(stackoverflow.com/questions/359494/…)。
Vicky Chijwani,2012年

101
基本上,我总是使用===它,因为它的工作方式与其他编程语言完全相同==。我认为==JavaScript不存在。
Vicky Chijwani,2012年

6
@de。在查找唯一值时,此处的许多答案提供了预期的行为。您基本上可以通过以下事实来识别它们:它们会尽早返回或中断循环(或指示较低级别的结构停止迭代)。请参阅JaredPar的答案以获取典型示例,以及Aaronius对该答案的评论以获取相同的见解。通常,人们以这种方式区分“过滤器”和“查找”功能,但是术语有所不同。尽管效率更高,但这仍然是线性搜索,因此,如果要使用哈希表,请参阅Aaron Digulla的答案(请注意隐含的详细信息)。
tne

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]...

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

由于ID和对象将被共享,因此不需要更多的内存。


6
正是我想要的。有趣的是我试图通过每次循环遍历来使它过于复杂,当我只需要对从CouchDB接收到的数据进行突变并将其转换成对我有用的格式时,就从列表中删除每个项目需要。+1先生!
slickplaid

5
这很聪明。我无法想象其他人如何通过遍历阵列的每次使用而被说服。
阿拉丁在13年

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

它无需外部库即可工作。但是,如果您希望使用较旧的浏览器支持,则可能需要包含此polyfill


1
可能是因为它似乎仍处于试验阶段,没有多少浏览器支持它, developer.mozilla.org
en

2
可以简化为myArray.find(d=>d.id===45).foo;
毛茸茸的

1
@蓬松甚至myArray.find(({ id }) => id === 45).foo。但这是一个古老的答案,它是在ES2015语法得到像现在这样的支持之前编写的。@Gothdo的答案是当前线程中最新的答案
朗尔·伯格

1
@Shaggy如果.find()返回未定义,则您的优化将引发错误。因此,只能在保证匹配的情况下使用此解决方案。
赫伯特·彼得斯

1
@HerbertPeters如果你想确保你可以送花儿给人空检查,这将是很容易与可选的链接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 2014年

如果只期望一个对象,则使用findWhere会更有效,因为找到一个结果之后,搜索将不会进行任何进一步的操作。
2015年

@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吗?
伊戈尔·季诺夫

@Igor Zinov'yev:是的,那些ES5阵列工具肯定会对性能产生影响。每个元素都会执行一个单独的函数,因此与直接for循环相比,它不会真正快。
pimvdb 2011年

所以您是说会慢一些吗?而且,据我所知,它将始终扫描整个数组,而for循环将在第一个匹配项时终止。
伊戈尔·齐诺夫

如果您需要对IE8的支持,只需将其放入:stackoverflow.com/questions/7153470/…–
亚当·格兰特

如果没有任何代码,此代码将引发错误id
Stan

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
Rick

12
如果您要提高效率,请注意,此示例可能比使用filter()更快(请参阅Rick的示例),因为一旦找到第一个匹配项,此示例就会返回,而filter()即使找到一个比赛。这也不需要为每个项目创建一个额外的数组或调用一个函数。
亚罗尼乌斯(Aaronius)2013年

3
@Rick,关于该答案的最有趣的事情显然是可以将firebug控制台添加到jsFiddle的输出窗口中。这比记录并告诉其他人打开控制台以查看输出要好得多。太棒了!
KyleMit 2014年

1
由于到目前为止还没有人提到它,所以我想补充一点,AngularJS也有一个filter方法。
2015年



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 2014年

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

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


请注意,IE8及以下版本不支持Array.reduce。
Burn_E99 '16

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

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

它对Arrays有很好的方法.find。因此,您可以找到这样的元素:

array.find( {id: 75} );

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

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


2
好吧,这邪恶的,因为新的EcmaScript版本可能会引入具有相同名称的新方法。猜猜是什么,这正是发生了什么find。我的建议是,如果要扩展本机原型,请始终使用更特定的名称,而将最简单的名称留给将来的标准开发。
MaxArt 2014年

此评论已有2年历史了,今天无论如何我还是希望使用lodash。但是,如果您愿意,可以在sugarjs网站上阅读有关此主题的信息。他们会很好地支持您的意见:sugarjs.com/native
deepflame 2014年

1
该操作人员确实确实要求使用JavaScript或jquery解决方案
Tobias Beuving 2015年

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


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

3

只要浏览器支持ECMA-262,第5版(2009年12月),它就可以工作,几乎只有一种形式:

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

2
几乎。bFound只是一个布尔值,true表示元素满足所需条件。
MaxArt 2014年

3

您甚至可以通过使用内置的数组“过滤器”函数在纯JavaScript中执行此操作:

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

16
不要修改您不拥有的对象。
米哈尔Perłakowski

3

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

演示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;
    });
}

如何在嵌套对象中搜索?像pets = false应该返回两个对象。
Valay

在嵌套循环中使用.filter方法obj.infovar getPerson = function(name){ return jsonObj.filter(function(obj) { return obj.info.filter(function(info) { return pets === false; }); }); }
Sumit Ridhal '17

您也可以使用es6样式... const filterData = jsonObj.filter(obj => obj.name ==='Alex')
DagicCross


2

我真的很喜欢亚伦·迪古拉(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 using 
	array[indexer[id]].property


使用最快的解决方案来查找数组中的项目。但是parseInt在这里是多余的。
aleha

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返回一个对象。


您可以通过使用return obj.id === 5来缩短代码?obj:false; 我经常使用$ .each遍历数组。
marcel

@marcel:那行不通。由于返回false将结束循环,因此只有在对象是数组中的第一项时,它才会找到对象。
Guffa 2015年

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
不要修改您不拥有的对象。
米哈尔Perłakowski

@我同意。如果有人不知道function will return the object, rather than an array可能会出错,但是我认为这取决于用户。
大豆

0

aggaton的答案开始,这是一个实际上返回null给定元素(如果没有找到的话)arraycallback函数,并且给出了一个返回“正确”元素的真实值的函数:

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之类的实用程序库。


0

最短的

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

1
这需要使用下划线库,OP要求使用简单的javascript或jQuery解决方案
Tobias Beuving 2015年

2
一旦包含下划线,这不是一个简短的答案!
Tim Ogilvy

-1

将“ 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;
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.