如何从JavaScript中的对象数组中获取不同的值?

假设我有以下几点:

var array = [ {"name":"Joe", "age":17}, {"name":"Bob", "age":17}, {"name":"Carl", "age": 35} ] 

能够获得所有不同年龄段的数组的最佳方法是什么,以便我得到一个结果数组:

 [17, 35] 

有没有什么办法可以select性地构造数据或更好的方法,这样我就不必遍历每个数组检查“年龄”的值,并检查另一个数组的存在,并添加它,如果不是?

如果有某种方式,我可以把不同的年龄拉出来…

目前我想要改进的方法不够…如果这意味着不是将“数组”作为一个对象数组,而是使用某个唯一键(即“1,2,3”)的对象的“映射”好吧。 我只是寻找最有效的方式。

以下是我目前如何做,但对我来说,迭代似乎只是效率低下,即使它工作…

 var distinct = [] for (var i = 0; i < array.length; i++) if (array[i].age not in distinct) distinct.push(array[i].age) 

如果这是PHP我会build立一个数组与键,并在最后采取array_keys ,但JS没有这样的奢侈品。 相反,试试这个:

 var flags = [], output = [], l = array.length, i; for( i=0; i<l; i++) { if( flags[array[i].age]) continue; flags[array[i].age] = true; output.push(array[i].age); } 

如果您使用ES6 / ES2015或更高版本,则可以这样做:

 var unique = [...new Set(array.map(item => item.age))]; 

这里是一个如何做到这一点的例子。

基于@Jonas Kello编辑build议:

 const unique = [...new Set(array.map(item => item.age))]; 

你可以使用像这样的字典方法。 基本上你把你想要分离的值作为字典中的键。 如果该键不存在,则将该值添加为不同的值。

 var unique = {}; var distinct = []; for( var i in array ){ if( typeof(unique[array[i].age]) == "undefined"){ distinct.push(array[i].age); } unique[array[i].age] = 0; } 

这是一个工作演示: http : //jsfiddle.net/jbUKP/1

这将是O(n),其中n是数组中的对象的数量,m是唯一值的数量。 没有比O(n)更快的方法,因为您必须检查每个值至less一次。

性能

http://jsperf.com/filter-versus-dictionary当我运行这个词典时快了30%。;

我只是映射和删除dups:

 var ages = array.map(function(obj) { return obj.age; }); ages = ages.filter(function(v,i) { return ages.indexOf(v) == i; }); console.log(ages); //=> [17, 35] 

编辑: Aight! 不是性能方面最有效的方式,而是最简单的最易读的IMO。 如果你真的关心微观优化或者你有大量的数据,那么定期for循环会更加“高效”。

使用ES6

 let array = [ { "name": "Joe", "age": 17 }, { "name": "Bob", "age": 17 }, { "name": "Carl", "age": 35 } ]; array.map(item => item.age) .filter((value, index, self) => self.indexOf(value) === index) > [17, 35] 

forEach版本的@travis-j的答案(对现代浏览器和Node JS世界有帮助):

 var unique = {}; var distinct = []; array.forEach(function (x) { if (!unique[x.age]) { distinct.push(x.age); unique[x.age] = true; } }); 

Chrome v29.0.1547上的速度提高了34%: http ://jsperf.com/filter-versus-dictionary/3

一个通用的解决scheme,需要一个映射函数(稍微比直接映射,但这是预期的):

 function uniqueBy(arr, fn) { var unique = {}; var distinct = []; arr.forEach(function (x) { var key = fn(x); if (!unique[key]) { distinct.push(key); unique[key] = true; } }); return distinct; } // usage uniqueBy(array, function(x){return x.age;}); // outputs [17, 35] 

我已经开始在所有新项目中默认使用Underscore,所以我从来不需要考虑这些小小的数据pipe理问题。

 var array = [{"name":"Joe", "age":17}, {"name":"Bob", "age":17}, {"name":"Carl", "age": 35}]; console.log(_.chain(array).map(function(item) { return item.age }).uniq().value()); 

产生[17, 35] 17,35 [17, 35]

使用lodash

 var array = [ { "name": "Joe", "age": 17 }, { "name": "Bob", "age": 17 }, { "name": "Carl", "age": 35 } ]; _.chain(array).pluck('age').unique().value(); > [17, 35] 

使用ES6function,您可以执行如下操作:

 const filteredValues = [...new Set( array.map(obj => obj.name)) ]; 

underscore.js _.uniq(_.pluck(array,"age"))

这是解决这个问题的另一种方法:

 var result = {}; for(var i in array) { result[array[i].age] = null; } result = Object.keys(result); 

我不知道这个解决scheme与其他解决scheme的速度有多快,但我喜欢更清洁的外观。 😉


编辑:好吧,上面似乎是所有这里最慢的解决scheme。

我在这里创build了一个性能testing用例: http : //jsperf.com/distinct-values-from-array

而不是testing年龄(整数),我select比较名称(string)。

方法1(TS的解决scheme)非常快。 有趣的是,方法7胜过所有其他的解决scheme,在这里我刚摆脱.indexOf(),并使用它的“手动”实现,避免循环函数调用:

 var result = []; loop1: for (var i = 0; i < array.length; i++) { var name = array[i].name; for (var i2 = 0; i2 < result.length; i2++) { if (result[i2] == name) { continue loop1; } } result.push(name); } 

使用Safari和Firefox的性能差异是惊人的,似乎Chrome在优化方面做得最好。

我不确定为什么上面的代码片段与其他代码相比如此之快,也许有人比我更聪明一个答案。 😉

使用Lodash

 var array = [ { "name": "Joe", "age": 17 }, { "name": "Bob", "age": 17 }, { "name": "Carl", "age": 35 } ]; _.chain(array).map('age').unique().value(); 

退货[17,35]

这是你如何解决这个问题,从2017年8月25日起,使用新的设置通过ES6打字稿

 Array.from(new Set(yourArray.map((item: any) => item.id))) 
 function get_unique_values_from_array_object(array,property){ var unique = {}; var distinct = []; for( var i in array ){ if( typeof(unique[array[i][property]]) == "undefined"){ distinct.push(array[i]); } unique[array[i][property]] = 0; } return distinct; } 

刚刚发现这一点,我认为这是有用的

 _.map(_.indexBy(records, '_id'), function(obj){return obj}) 

再次使用下划线 ,所以如果你有这样一个对象

 var records = [{_id:1,name:'one', _id:2,name:'two', _id:1,name:'one'}] 

它只会给你唯一的对象。

这里发生的是indexBy像这样返回一个映射

 { 1:{_id:1,name:'one'}, 2:{_id:2,name:'two'} } 

只是因为它是一张地图,所有的钥匙都是独一无二的。

然后我只是将这个列表映射回数组。

如果你只需要不同的值

 _.map(_.indexBy(records, '_id'), function(obj,key){return key}) 

请记住, key是以stringforms返回的,所以如果你需要整数,你应该这样做

 _.map(_.indexBy(records, '_id'), function(obj,key){return parseInt(key)}) 

如果像我一样,你更喜欢一个更“function”而不影响速度,这个例子使用快速字典查找包装内减less封闭。

 var array = [ {"name":"Joe", "age":17}, {"name":"Bob", "age":17}, {"name":"Carl", "age": 35} ] var uniqueAges = array.reduce((p,c,i,a) => { if(!p[0][c.age]) { p[1].push(p[0][c.age] = c.age); } if(i<a.length-1) { return p } else { return p[1] } }, [{},[]]) 

根据这个testing,我的解决scheme是build议答案的两倍

我认为你正在寻找groupBy函数(使用Lodash)

 _personsList = [{"name":"Joe", "age":17}, {"name":"Bob", "age":17}, {"name":"Carl", "age": 35}]; _uniqAgeList = _.groupBy(_personsList,"age"); _uniqAges = Object.keys(_uniqAgeList); 

产生结果:

 17,35 

jsFiddle演示: http : //jsfiddle.net/4J2SX/201/

如果你有Array.prototype.includes或愿意填充它,这工作:

 var ages = []; array.forEach(function(x) { if (!ages.includes(x.age)) ages.push(x.age); }); 

这是一个多用途的解决scheme,使用减less,允许映射和维护插入顺序。

项目 :一个数组

映射器(mapper) :将项目映射到条件的一元函数,或者为空映射项目本身。

 function distinct(items, mapper) { if (!mapper) mapper = (item)=>item; return items.map(mapper).reduce((acc, item) => { if (acc.indexOf(item) === -1) acc.push(item); return acc; }, []); } 

用法

 const distinctLastNames = distinct(items, (item)=>item.lastName); const distinctItems = distinct(items); 

你可以添加这个到你的数组原型,如果这是你的风格,可以省略items参数。

 const distinctLastNames = items.distinct( (item)=>item.lastName) ) ; const distinctItems = items.distinct() ; 

您也可以使用Set而不是Array来加速匹配。

 function distinct(items, mapper) { if (!mapper) mapper = (item)=>item; return items.map(mapper).reduce((acc, item) => { acc.add(item); return acc; }, new Set()); } 

我在这个function上的两分钱:

 var result = []; for (var len = array.length, i = 0; i < len; ++i) { var age = array[i].age; if (result.indexOf(age) > -1) continue; result.push(age); } 

你可以在这里看到结果(方法8) http://jsperf.com/distinct-values-from-array/3

使用新的Ecmafunction是伟大的,但并不是所有的用户都有可用的。

以下代码将附加一个名为distinct的新函数给全局数组对象。 如果您正在尝试获取对象数组的不同值,则可以传递该值的名称以获取该types的不同值。

 Array.prototype.distinct = function(item){ var results = []; for (var i = 0, l = this.length; i < l; i++) if (!item){ if (results.indexOf(this[i]) === -1) results.push(this[i]); } else { if (results.indexOf(this[i][item]) === -1) results.push(this[i][item]); } return results;}; 

看看我的post CodePen的演示。

你试一试

 var x = [] ; for (var i = 0 ; i < array.length ; i++) { if(x.indexOf(array[i]['age']) == -1) { x.push(array[i]['age']); } } console.log(x); 

使用d3.js v3 :

  ages = d3.set( array.map(function (d) { return d.age; }) ).values(); 
 unique(obj, prop) { let result = []; let seen = new Set(); Object.keys(obj) .forEach((key) => { let value = obj[key]; let test = !prop ? value : value[prop]; !seen.has(test) && seen.add(test) && result.push(value); }); return result; } 

这个函数可以有唯一的数组和对象

 function oaunic(x,n=0){ if(n==0) n = "elem"; else n = "elem."+n; var uval = []; var unic = x.filter(function(elem, index, self){ if(uval.indexOf(eval(n)) < 0){ uval.push(eval(n)); return index == self.indexOf(elem); } }) return unic; } 

像这样使用

 tags_obj = [{name:"milad"},{name:"maziar"},{name:"maziar"}] tags_arr = ["milad","maziar","maziar"] console.log(oaunic(tags_obj,"name")) //for object console.log(oaunic(tags_arr)) //for array