896

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 inefficient 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. I'm 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)
6
  • 78
    iteration isn't "crummy for efficiency" and you can't do anything to every element "without iterating". you can use various functional-looking methods, but ultimately, something on some level has to iterate over the items. Commented Feb 28, 2013 at 1:47
  • //100% running code 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) ); console.log(filtered); Commented Nov 7, 2019 at 12:15
  • 2
    the bounty is great, but the question with the given data and answer is already answered here: stackoverflow.com/questions/53542882/…. what is the purpose of the bounty? should i answer this particular problem with two or more keys? Commented Nov 8, 2019 at 8:59
  • 2
    Set object and maps are wasteful. This job just takes a simple .reduce() stage. Commented Nov 13, 2019 at 19:37
  • Please check this example, stackoverflow.com/a/58944998/13013258 . Commented May 19, 2021 at 8:08

65 Answers 65

1 2
3
-1

my two cents on this 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);
}

You can see the result here (Method 8) http://jsperf.com/distinct-values-from-array/3

Sign up to request clarification or add additional context in comments.

Comments

-1

If you would like to filter out duplicate values from an array on a known unique object property, you could use the following snippet:

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()]

1 Comment

I don't know why this answer got down voted. You can change map.set(val.name, val); statement to match your desired distinct output including the object itself as in the example or a property of it like this: map.set(val.name, val.name);
-2

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

Comments

-2

I know this is an old and relatively well-answered question and the answer I'm giving will get the complete-object back (Which I see suggested in a lot of the comments on this post). It may be "tacky" but in terms of readability seems a lot cleaner (although less efficient) than a lot of other solutions.

This will return a unique array of the complete objects inside the array.

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

1 Comment

Not JSON.stringify, but rather npmjs.com/package/json-stable-stringify or npmjs.com/package/es6-json-stable-stringify is needed. JSON.parse is OK.
-6

using d3.js v3:

  ages = d3.set(
    array.map(function (d) { return d.age; })
  ).values();

1 Comment

Why to use D3 when the same function is available in pure JS?
1 2
3

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.