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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15125920/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-26 23:35:58  来源:igfitidea点击:

How to get distinct values from an array of objects in JavaScript?

javascriptarraysunique

提问by Rolando

Assuming I have the following:

假设我有以下内容:

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

What is the best way to be able to get an array of all of the distinct ages such that I get an result array of:

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

[17, 35]

Is there some way I could alternatively structure the data or better method such that I would not have to iterate through each array checking the value of "age" and check against another array for its existence, and add it if not?

有什么方法可以替代地构造数据或更好的方法,这样我就不必遍历每个数组来检查“age”的值并检查另一个数组是否存在,如果不存在则添加它?

If there was some way I could just pull out the distinct ages without iterating...

如果有某种方法我可以在不迭代的情况下提取不同的年龄......

Current inefficent way I would like to improve... If it means that instead of "array" being an array of objects, but a "map" of objects with some unique key (i.e. "1,2,3") that would be okay too. Im just looking for the most performance efficient way.

目前我想改进的低效方式......如果这意味着不是“数组”是一个对象数组,而是一个具有某些唯一键(即“1,2,3”)的对象“映射”,那将是也可以。我只是在寻找最高效的方式。

The following is how I currently do it, but for me, iteration appears to just be crummy for efficiency even though it does work...

以下是我目前的做法,但对我来说,迭代似乎只是效率低下,即使它确实有效......

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

采纳答案by Niet the Dark Absol

If this were PHP I'd build an array with the keys and take array_keysat the end, but JS has no such luxury. Instead, try this:

如果这是 PHP,我会用键构建一个数组并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);
}

回答by Vlad Bezden

If you are using ES6/ES2015 or later you can do it this way:

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

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

Hereis an example on how to do it.

是有关如何执行操作的示例。

回答by Ivan Nosov

using ES6

使用 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]

回答by Travis J

You could use a dictionary approach like this one. Basically you assign the value you want to be distinct as a key in the "dictionary" (here we use an array as an object to avoid dictionary-mode). If the key did not exist then you add that value as distinct.

您可以使用这样的字典方法。基本上,您将想要区分的值分配为“字典”中的键(这里我们使用数组作为对象以避免字典模式)。如果该键不存在,则将该值添加为不同的。

Here is a working demo:

这是一个工作演示:

var array = [{"name":"Joe", "age":17}, {"name":"Bob", "age":17}, {"name":"Carl", "age": 35}];
var unique = [];
var distinct = [];
for( let i = 0; i < array.length; i++ ){
  if( !unique[array[i].age]){
    distinct.push(array[i].age);
    unique[array[i].age] = 1;
  }
}
var d = document.getElementById("d");
d.innerHTML = "" + distinct;
<div id="d"></div>

This will be O(n) where n is the number of objects in array and m is the number of unique values. There is no faster way than O(n) because you must inspect each value at least once.

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

The previous version of this used an object, and for in. These were minor in nature, and have since been minorly updated above. However, the reason for a seeming advance in performance between the two versions in the original jsperf was due to the data sample size being so small. Thus, the main comparison in the previous version was looking at the difference between the internal map and filter use versus the dictionary mode lookups.

以前的版本使用了一个对象,并为 in。这些本质上是次要的,并且已经在上面进行了小幅更新。但是,原始 jsperf 中两个版本之间的性能似乎有所提高的原因是数据样本量太小。因此,之前版本中的主要比较是查看内部映射和过滤器使用与字典模式查找之间的差异。

I have updated the code above, as noted, however, I have also updated the jsperf to look through 1000 objects instead of 3. 3 overlooked many of the performance pitfalls involved (obsolete jsperf).

如上所述,我已经更新了上面的代码,但是,我还更新了 jsperf 以查看 1000 个对象,而不是 3 个。3 忽略了所涉及的许多性能陷阱(过时的 jsperf)。

Performance

表现

https://jsperf.com/filter-vs-dictionary-more-dataWhen I ran this dictionary was 96% faster.

https://jsperf.com/filter-vs-dictionary-more-data当我运行这本词典时,速度提高了 96%。

filter vs dictionary

过滤器与字典

回答by Christian Matthew

This is how you would solve this using new Set via ES6 for Typescript as of August 25th, 2017

这是截至 2017 年 8 月 25 日,您将如何使用新的 Set via ES6 for Typescript 解决此问题

Array.from(new Set(yourArray.map((item: any) => item.id)))

回答by Russell Vea

Using ES6 features, you could do something like:

使用 ES6 特性,您可以执行以下操作:

const uniqueAges = [...new Set( array.map(obj => obj.age)) ];

回答by elclanrs

I'd just map and remove 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]

Edit:Aight! Not the most efficient way in terms of performance, but the simplest most readable IMO. If you really care about micro-optimization or you have huge amounts of data then a regular forloop is going to be more "efficient".

编辑:对了!就性能而言,这不是最有效的方式,而是最简单、最易读的 IMO。如果您真的关心微优化或者您有大量数据,那么常规for循环将更加“有效”。

回答by oleg gabureac

var unique = array
    .map(p => p.age)
    .filter((age, index, arr) => arr.indexOf(age) == index)
    .sort(); // sorting is optional

// or in ES6

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

// or with lodash

var unique = _.uniq(_.map(array, 'age'));

ES6 example

ES6 示例

const data = [
  { name: "Joe", age: 17}, 
  { name: "Bob", age: 17}, 
  { name: "Carl", age: 35}
];

const arr = data.map(p => p.age); // [17, 17, 35]
const s = new Set(arr); // {17, 35} a set removes duplications, but it's still a set
const unique = [...s]; // [17, 35] Use the spread operator to transform a set into an Array
// or use Array.from to transform a set into an array
const unique2 = Array.from(s); // [17, 35]

回答by Arun Kumar Saini

For those who want to return object with all properties unique by key

对于那些想要返回具有键唯一属性的对象的人

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

const key = 'age';

const arrayUniqueByKey = [...new Map(array.map(item =>
  [item[key], item])).values()];

console.log(arrayUniqueByKey);

   /*OUTPUT
       [
        { "name": "Bob", "age": 17 },
        { "name": "Carl", "age": 35 }
       ]
   */

 // Note: this will pick the last duplicated item in the list.

回答by Harry Stevens

There are many valid answers already, but I wanted to add one that uses only the reduce()method because it is clean and simple.

已经有很多有效的答案,但我想添加一个只使用该reduce()方法的答案, 因为它干净简单。

function uniqueBy(arr, prop){
  return arr.reduce((a, d) => {
    if (!a.includes(d[prop])) { a.push(d[prop]); }
    return a;
  }, []);
}

Use it like this:

像这样使用它:

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

var ages = uniqueBy(array, "age");
console.log(ages); // [17, 35]