How to get distinct values from an array of object

2019-01-01 08:08发布

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?

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.

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)

27条回答
回忆,回不去的记忆
2楼-- · 2019-01-01 08:35

The forEach version of @travis-j's answer (helpful on modern browsers and Node JS world):

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

34% faster on Chrome v29.0.1547: http://jsperf.com/filter-versus-dictionary/3

And a generic solution that takes a mapper function (tad slower than direct map, but that's expected):

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]
查看更多
若你有天会懂
3楼-- · 2019-01-01 08:35

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

查看更多
人间绝色
4楼-- · 2019-01-01 08:36

this function can unique array and object

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

use that like this

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
查看更多
大哥的爱人
5楼-- · 2019-01-01 08:38

Here's a versatile solution that uses reduce, allows for mapping, and maintains insertion order.

items: An array

mapper: A unary function that maps the item to the criteria, or empty to map the item itself.

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

Usage

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

You can add this to your Array prototype and leave out the items parameter if that's your style...

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

You can also use a Set instead of an Array to speed up the matching.

function distinct(items, mapper) {
    if (!mapper) mapper = (item)=>item;
    return items.map(mapper).reduce((acc, item) => {
        acc.add(item);
        return acc;
    }, new Set());
}
查看更多
看淡一切
6楼-- · 2019-01-01 08:39

Using ES6 features, you could do something like:

const uniqueAges = [...new Set( array.map(obj => obj.age)) ];
查看更多
骚的不知所云
7楼-- · 2019-01-01 08:39

Using new Ecma features are great but not all users have those available yet.

Following code will attach a new function named distinct to the Global Array object. If you are trying get distinct values of an array of objects, you can pass the name of the value to get the distinct values of that type.

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

Check out my post in CodePen for a demo.

查看更多
登录 后发表回答