660

假设我有以下内容:

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

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

[17, 35]

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

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

我想改进的当前低效方式......如果这意味着不是“数组”是一个对象数组,而是一个具有一些唯一键(即“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)
4

58 回答 58

1047

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

const data = [
  { group: 'A', name: 'SD' }, 
  { group: 'B', name: 'FI' }, 
  { group: 'A', name: 'MM' },
  { group: 'B', name: 'CO'}
];
const unique = [...new Set(data.map(item => item.group))]; // [ 'A', 'B']

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

于 2016-01-29T19:31:14.317 回答
277

使用 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]
于 2015-12-10T10:23:43.963 回答
233

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

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.

于 2019-10-17T09:52:51.453 回答
155

如果这是 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);
}
于 2013-02-28T01:36:10.203 回答
152

使用 ES6 功能,您可以执行以下操作:

const uniqueAges = [...new Set( array.map(obj => obj.age)) ];
于 2015-11-04T01:37:23.127 回答
148

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

这是一个工作演示:

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>

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

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

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

表现

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

过滤器与字典

于 2013-02-28T01:37:15.447 回答
137

从 2017 年 8 月 25 日起,您将通过 ES6 for Typescript 使用新的 Set 来解决此问题

Array.from(new Set(yourArray.map((item: any) => item.id)))
于 2017-08-25T16:50:07.937 回答
69

我只是映射和删除重复:

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]

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

于 2013-02-28T01:40:26.913 回答
49
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 示例

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]
于 2018-12-16T16:18:26.380 回答
33

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

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

像这样使用它:

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

var ages = uniqueBy(array, "age");
console.log(ages); // [17, 35]
于 2018-08-02T13:39:58.867 回答
26

const array = [
  {"id":"93","name":"CVAM_NGP_KW"},
  {"id":"94","name":"CVAM_NGP_PB"},
  {"id":"93","name":"CVAM_NGP_KW"},
  {"id":"94","name":"CVAM_NGP_PB"}
]

function uniq(array, field) {
  return array.reduce((accumulator, current) => {
      if(!accumulator.includes(current[field])) {
        accumulator.push(current[field])
      }
      return accumulator;
    }, []
  )
}

const ids = uniq(array, 'id');
console.log(ids)

/* output 
["93", "94"]
*/

于 2019-08-12T22:08:17.823 回答
22

@travis-j的forEach答案版本(对现代浏览器和 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

还有一个采用映射器函数的通用解决方案(比直接映射慢一点,但这是意料之中的):

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]
于 2013-09-20T18:28:17.980 回答
22

我有一个小解决方案

let data = [{id: 1}, {id: 2}, {id: 3}, {id: 2}, {id: 3}];

let result = data.filter((value, index, self) => self.findIndex((m) => m.id === value.id) === index);
于 2021-01-21T14:11:30.413 回答
17

我已经开始在所有新项目中默认使用下划线,这样我就不必考虑这些小的数据处理问题。

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

于 2013-02-28T01:45:51.690 回答
13

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

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

我不知道这个解决方案与其他解决方案相比有多快,但我喜欢更简洁的外观。;-)


编辑:好的,以上似乎是这里最慢的解决方案。

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

我没有测试年龄(整数),而是选择比较名称(字符串)。

方法1(TS的解决方案)非常快。有趣的是,方法 7 优于所有其他解决方案,在这里我只是摆脱了 .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 在优化方面做得最好。

我不确定为什么上述片段与其他片段相比如此之快,也许比我更聪明的人有答案。;-)

于 2015-02-13T17:47:46.947 回答
11

使用lodash

var array = [
    { "name": "Joe", "age": 17 },
    { "name": "Bob", "age": 17 },
    { "name": "Carl", "age": 35 }
];
_.chain(array).pluck('age').unique().value();
> [17, 35]
于 2015-01-21T14:01:59.007 回答
11

如果您需要整个对象,这与 ES6 版本略有不同:

let arr = [
    {"name":"Joe", "age":17}, 
    {"name":"Bob", "age":17}, 
    {"name":"Carl", "age": 35}
]
arr.filter((a, i) => arr.findIndex((s) => a.age === s.age) === i) // [{"name":"Joe", "age":17}, {"name":"Carl", "age": 35}]
于 2021-04-29T17:11:17.893 回答
10

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

      const ages = [...new Set(array.reduce((a, c) => [...a, c.age], []))];
    
      console.log(ages);

于 2021-04-12T01:57:58.417 回答
9

使用 Maps 的简单不同过滤器:

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

let data = new Map();

for (let obj of array) {
  data.set(obj.age, obj);
}

let out = [...data.values()];

console.log(out);

于 2020-08-05T23:05:42.963 回答
7

使用Lodash

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

_.chain(array).map('age').unique().value();

返回 [17,35]

于 2016-11-29T11:10:10.110 回答
7

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

于 2021-10-16T22:30:22.583 回答
6
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;
}
于 2015-12-30T13:35:13.610 回答
5

下划线.js _.uniq(_.pluck(array,"age"))

于 2016-05-02T17:24:06.173 回答
5

这是一个使用reduce、允许映射和维护插入顺序的通用解决方案。

项目:一个数组

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

如果这是您的风格,您可以将其添加到您的 Array 原型中并省略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());
}
于 2017-01-18T13:52:40.793 回答
5

如果您想返回一个唯一的对象列表。这是另一种选择:

const unique = (arr, encoder=JSON.stringify, decoder=JSON.parse) =>
  [...new Set(arr.map(item => encoder(item)))].map(item => decoder(item));

这将变成这样:

unique([{"name": "john"}, {"name": "sarah"}, {"name": "john"}])

进入

[{"name": "john"}, {"name": "sarah"}]

这里的诀窍是,我们首先使用 将项目编码为字符串JSON.stringify,然后将其转换为 Set(这使得字符串列表唯一),然后使用 将其转换回原始对象JSON.parse

于 2020-07-07T13:54:05.120 回答
4

刚找到这个,我认为它很有用

_.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是作为字符串返回的,因此,如果您需要整数,则应该这样做

_.map(_.indexBy(records, '_id'), function(obj,key){return parseInt(key)})
于 2014-07-23T12:10:31.523 回答
4

我认为您正在寻找 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/

于 2017-05-10T12:16:16.443 回答
4
[...new Set([
    { "name": "Joe", "age": 17 },
    { "name": "Bob", "age": 17 },
    { "name": "Carl", "age": 35 }
  ].map(({ age }) => age))]
于 2019-10-24T08:00:47.207 回答
4

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

    console.log(Object.keys(array.reduce((r,{age}) => (r[age]='', r) , {})))

输出:

Array ["17", "35"]
于 2021-07-16T18:05:28.170 回答
3

如果您有 Array.prototype.includes 或愿意对其进行polyfill,则可以:

var ages = []; array.forEach(function(x) { if (!ages.includes(x.age)) ages.push(x.age); });
于 2015-05-20T23:13:22.433 回答
3

如果像我一样,您更喜欢在不影响速度的情况下更“实用”,这个例子使用包装在 reduce 闭包中的快速字典查找。

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]
    }
}, [{},[]])

根据这个测试,我的解决方案是建议答案的两倍

于 2016-01-31T06:54:21.317 回答
3

我知道我的代码长度和时间复杂度都很短,但这是可以理解的,所以我尝试了这种方式。

我正在尝试在这里开发基于原型的功能,并且代码也发生了变化。

这里,Distinct是我自己的原型函数。

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

  Array.prototype.Distinct = () => {
    var output = [];
    for (let i = 0; i < array.length; i++) {
      let flag = true;
      for (let j = 0; j < output.length; j++) {
        if (array[i].age == output[j]) {
          flag = false;
          break;
        }
      }
      if (flag)
        output.push(array[i].age);
    }
    return output;
  }
  //Distinct is my own function
  console.log(array.Distinct());
</script>

于 2019-11-12T14:23:18.647 回答
2

简单的单线具有出色的性能。在我的测试中比 ES6 解决方案快 6% 。

var ages = array.map(function(o){return o.age}).filter(function(v,i,a) {
    return a.indexOf(v)===i
});
于 2019-04-30T07:21:41.607 回答
2

这里有很多很好的答案,但没有一个解决了以下问题:

有什么方法可以替代地构建数据

我会创建一个对象,其键是年龄,每个都指向一个名称数组。

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

var map = array.reduce(function(result, item) {
  result[item.age] = result[item.age] || [];
  result[item.age].push(item.name);
  return result;
}, {});

console.log(Object.keys(map));
console.log(map);

通过这种方式,您已将数据结构转换为一种非常容易从中检索不同年龄的数据结构。

这是一个更紧凑的版本,它还存储整个对象而不仅仅是名称(如果您正在处理具有超过 2 个属性的对象,因此它们不能存储为键和值)。

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

var map = array.reduce((r, i) => ((r[i.age] = r[i.age] || []).push(i), r), {});

console.log(Object.keys(map));
console.log(map);

于 2019-11-12T08:13:49.993 回答
2

原始类型

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

对于复杂类型,例如对象

var unique = [...new DeepSet(array.map(item => item.Object))];

export class DeepSet extends Set {

  add (o: any) {
    for (let i of this)
      if (this.deepCompare(o, i))
        return this;
    super.add.call(this, o);
    return this;
  };

  private deepCompare(o: any, i: any) {
    return JSON.stringify(o) === JSON.stringify(i)
  }
}

于 2021-04-20T11:06:31.337 回答
2

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

const uniqueArrayByProperty = (array, callback) => {
  return array.reduce((prev, item) => {
    const v = callback(item);    
    if (!prev.includes(v)) prev.push(v)          
    return prev
  }, [])    
}

console.log(uniqueArrayByProperty(array, it => it.age));

于 2021-05-17T14:09:07.550 回答
1

我下面的代码将显示唯一的年龄数组以及没有重复年龄的新数组

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

var unique = [];
var tempArr = [];
data.forEach((value, index) => {
    if (unique.indexOf(value.age) === -1) {
        unique.push(value.age);
    } else {
        tempArr.push(index);    
    }
});
tempArr.reverse();
tempArr.forEach(ele => {
    data.splice(ele, 1);
});
console.log('Unique Ages', unique);
console.log('Unique Array', data);```
于 2019-05-10T10:30:07.997 回答
1

我用 TypeScript 编写了自己的通用案例,就像 Kotlin 的Array.distinctBy {}...

function distinctBy<T, U extends string | number>(array: T[], mapFn: (el: T) => U) {
  const uniqueKeys = new Set(array.map(mapFn));
  return array.filter((el) => uniqueKeys.has(mapFn(el)));
}

哪里U是可散列的,当然。对于对象,您可能需要https://www.npmjs.com/package/es6-json-stable-stringify

于 2019-08-27T10:40:10.603 回答
1

如果您需要整个对象的唯一性

const _ = require('lodash');

var objects = [
  { 'x': 1, 'y': 2 },
  { 'y': 1, 'x': 2 },
  { 'x': 2, 'y': 1 },
  { 'x': 1, 'y': 2 }
];

_.uniqWith(objects, _.isEqual);

[对象{x:1,y:2},对象{x:2,y:1}]

于 2019-10-10T10:34:28.540 回答
1

回答这个老问题毫无意义,但是有一个简单的答案可以说明 Javascript 的本质。Javascript 中的对象本质上是哈希表。我们可以使用它来获取唯一键的哈希:

var o = {}; array.map(function(v){ o[v.age] = 1; });

然后我们可以将散列简化为一个唯一值数组:

var a2 = []; for (k in o){ a2.push(k); }

这就是你所需要的。数组a2仅包含唯一的年龄。

于 2019-11-14T02:54:22.880 回答
1

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

const allAges = array.map(a => a.age);

const uniqueSet = new Set(allAges)
const uniqueArray = [...uniqueSet]

console.log(uniqueArray)

于 2020-01-09T21:40:27.790 回答
1

linq.js - LINQ for JavaScript包 (npm install linq),对于 .Net 开发人员来说应该很熟悉。

示例中显示的其他方法中, 存在明显的重载。

通过属性值从对象数组中区分对象的示例是

Enumerable.from(array).distinct(“$.id”).toArray();

来自https://medium.com/@xmedeko/i-recommend-you-to-try-https-github-com-mihaifm-linq-20a4e3c090e9

于 2020-05-09T05:55:59.587 回答
1

我选择了随机样本并针对以下 100,000 个项目进行了测试:

let array=[]
for (var i=1;i<100000;i++){

 let j= Math.floor(Math.random() * i) + 1
  array.push({"name":"Joe"+j, "age":j})
}

这里是每个的性能结果:

  Vlad Bezden Time:         === > 15ms
  Travis J Time: 25ms       === > 25ms 
  Niet the Dark Absol Time: === > 30ms
  Arun Saini Time:          === > 31ms
  Mrchief Time:             === > 54ms
  Ivan Nosov Time:          === > 14374ms

另外,我想提一下,由于这些项目是随机生成的,因此第二位是在 Travis 和 Niet 之间进行迭代。

于 2020-09-29T03:52:12.230 回答
1

假设我们有这样的数据arr=[{id:1,age:17},{id:2,age:19} ...],那么我们可以找到这样的独特对象 -

function getUniqueObjects(ObjectArray) {
    let uniqueIds = new Set();
    const list = [...new Set(ObjectArray.filter(obj => {
        if (!uniqueIds.has(obj.id)) {
            uniqueIds.add(obj.id);
            return obj;
        }
    }))];

    return list;
}

在这里查看Codepen 链接

于 2021-02-13T12:30:49.373 回答
0

使用新的 Ecma 功能很棒,但并非所有用户都拥有这些功能。

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

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

查看在 CodePen 中的帖子以获取演示。

于 2017-03-28T17:59:50.843 回答
0
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;
}
于 2017-10-10T22:48:56.583 回答
0

好吧,您可以使用 lodash 编写一个不那么冗长的代码

方法一:嵌套方法

    let array = 
        [
            {"name":"Joe", "age":17}, 
            {"name":"Bob", "age":17}, 
            {"name":"Carl", "age": 35}
        ]
    let result = _.uniq(_.map(array,item=>item.age))

方法 2:方法链接或级联方法

    let array = 
        [
            {"name":"Joe", "age":17}, 
            {"name":"Bob", "age":17}, 
            {"name":"Carl", "age": 35}
        ]
    let result = _.chain(array).map(item=>item.age).uniq().value()

您可以从https://lodash.com/docs/4.17.15#uniq了解 lodash 的 uniq() 方法

于 2019-11-13T07:46:17.677 回答
0

从一组键中获取不同值的集合的方法。

您可以从此处获取给定的代码,并仅为想要的键添加映射以获取唯一对象值的数组。

const
    listOfTags = [{ id: 1, label: "Hello", color: "red", sorting: 0 }, { id: 2, label: "World", color: "green", sorting: 1 }, { id: 3, label: "Hello", color: "blue", sorting: 4 }, { id: 4, label: "Sunshine", color: "yellow", sorting: 5 }, { id: 5, label: "Hello", color: "red", sorting: 6 }],
    keys = ['label', 'color'],
    filtered = listOfTags.filter(
        (s => o =>
            (k => !s.has(k) && s.add(k))
            (keys.map(k => o[k]).join('|'))
        )(new Set)
    )
    result = filtered.map(o => Object.fromEntries(keys.map(k => [k, o[k]])));

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

于 2019-11-13T17:07:11.773 回答
0

使用集合和过滤器。这保留了顺序:

let unique = (items) => {
    const s = new Set();
    return items.filter((item) => {
      if (s.has(item)) {
        return false;
      }
      s.add(item);
      return true;
    });
  }
  
  console.log(
  unique(
      [
        'one', 'two', 'two', 'three', 'three', 'three'
      ]
    )
  );

/*
output:
[
  "one",
  "two",
  "three"
]
*/

于 2020-02-24T21:00:31.300 回答
0

如果您在使用 ES5 时遇到问题,new Set或者new Map由于某种原因无法使用,并且您需要一个包含具有唯一键的值的数组(而不仅仅是一个唯一键的数组),您可以使用以下命令:

function distinctBy(key, array) {
    var keys = array.map(function (value) { return value[key]; });
    return array.filter(function (value, index) { return keys.indexOf(value[key]) === index; });
}

或者 TypeScript 中的类型安全等价物:

public distinctBy<T>(key: keyof T, array: T[]) {
    const keys = array.map(value => value[key]);
    return array.filter((value, index) => keys.indexOf(value[key]) === index);
}

用法:

var distinctPeople = distinctBy('age', people);

所有其他答案:

  • 返回唯一键数组而不是对象(例如返回年龄列表而不是具有唯一年龄的人);
  • 使用您可能无法使用的ES6new Set等;new Map
  • 没有可配置的键(比如.age硬编码到 distinct 函数中);
  • 假设键可用于索引数组,这并不总是正确的,TypeScript 不允许这样做。

这个答案不存在上述四个问题中的任何一个。

于 2020-12-18T10:19:01.103 回答
0

如果您的数组是对象数组,则可以使用此代码。

getUniqueArray = (array: MyData[]) => {
    return array.filter((elem, index) => array.findIndex(obj => obj.value == elem.value) === index);
}

MyData 如下所示:

export interface MyData{
    value: string,
    name: string
}

注意:您不能使用 Set,因为在比较对象时,它们是按引用而不是按值进行比较的。因此,您需要唯一键来比较对象,在我的示例中,唯一键是值字段。有关更多详细信息,您可以访问此链接:Filter an array for unique values in Javascript

于 2021-01-18T19:06:38.067 回答
0

let mobilePhones = [{id: 1, brand: "B1"}, {id: 2, brand: "B2"}, {id: 3, brand: "B1"}, {id: 4, brand: "B1"}, {id: 5, brand: "B2"}, {id: 6, brand: "B3"}]
 let allBrandsArr = mobilePhones .map(row=>{
        return  row.brand;
      });
let uniqueBrands =   allBrandsArr.filter((item, index, arry) => (arry.indexOf(item) === index));
console.log('uniqueBrands   ', uniqueBrands );

于 2021-07-20T06:32:56.383 回答
0

使用iter-ops库的高效和干净的方法:

import {pipe, distinct, map} from 'iter-ops';

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

const i = pipe(
    array,
    distinct(a => a.age),
    map(m => m.age)
);

const uniqueAges = [...i]; //=> [17, 35]
于 2021-11-16T14:49:17.540 回答
-1

我在这个功能上的两分钱:

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

于 2015-03-31T13:17:27.040 回答
-1

如果您想从已知唯一对象属性的数组中过滤掉重复值,可以使用以下代码段:

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

let uniqueValues = [...arr.reduce((map, val) => {
    if (!map.has(val.name)) {
        map.set(val.name, val);
    }
    return map;
}, new Map()).values()]
于 2019-09-21T17:43:01.840 回答
-2

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

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
于 2017-11-09T06:09:49.813 回答
-2

我知道这是一个古老且答案相对较好的问题,我给出的答案将得到完整的对象(我在这篇文章的很多评论中看到了这一点)。它可能“俗气”,但在可读性方面似乎比许多其他解决方案更干净(尽管效率较低)。

这将返回数组内完整对象的唯一数组。

let productIds = data.map(d => { 
   return JSON.stringify({ 
      id    : d.sku.product.productId,
      name  : d.sku.product.name,
      price : `${d.sku.product.price.currency} ${(d.sku.product.price.gross / d.sku.product.price.divisor).toFixed(2)}`
   })
})
productIds = [ ...new Set(productIds)].map(d => JSON.parse(d))```
于 2019-07-14T08:40:06.383 回答
-5

使用d3.js v3

  ages = d3.set(
    array.map(function (d) { return d.age; })
  ).values();
于 2017-07-26T11:52:19.210 回答