Jeff Storey
Jeff Storey

Reputation: 57192

concise javascript to get all unique values for a particular key

I have a javascript array, and I want to get all unique values for a particular key. I have implemented it using underscore like this:

var v = { "b" : 2 };
var w = { "a" : 4, "b" : 2 };
var x = { "a" : 1, "b" : 2 };
var y = { "a" : 4, "b" : 2, "c" : 3 };
var z = { "a" : null, "b" : 2, "c" : 3 };
var data = [v,w,x,y,z];

// this is the part I'd like to make more concise
var keys = _.map(data,function(d) { return d.a; });
keys = _.unique(keys);
keys = _.reject(keys, function(k) { return _.isUndefined(k) || _.isNull(k)});

http://jsfiddle.net/Gc4tJ/

It seems like there should be a more compact way to do this, but I can't quite figure out if there is. I don't need to use underscore here either. I'm using d3 but couldn't quite figure out a simpler way to do this in d3 either.

Upvotes: 3

Views: 2225

Answers (3)

JW Buitenhuis
JW Buitenhuis

Reputation: 41

Could you filter on truthy values?

_.uniq(data.map(d => d.a).filter(d => d))

Upvotes: 0

Adam Pearce
Adam Pearce

Reputation: 9293

If you're ok with the a property being cast to a string, you can use d3.set. Without underscore, correctly checking for null and undefined is a little cumbersome, it might make sense to create your own function to do so:

keys = d3.set(
    data.map(function(d){ return d.a; })
        .filter(function(d){  return (typeof d !== "undefined") ? d !== null : false })
    ).values();

Just using vanilla javascript is a little longer, but doesn't cast to strings:

keys = data.map(function(d){ return d.a; })
     .reduce(function(p, v){ return p.indexOf(v) == -1 ? p.concat(v) : p; }, [])
     .filter(function(d){  return (typeof d !== "undefined") ? d !== null : false });

As Bergi points out, you could also use chaining to make your underscore code more concise.

For more underscore/javascript/d3 comparisons, Mike Bostock updated a gist with equivalents between them a few weeks ago. I've added a few more, but they start getting pretty tricky/harder to understand.

Upvotes: 1

Bergi
Bergi

Reputation: 664650

You could simplify by using the pluck method. Also, the reject thing could be shortened by using either compact or without.

var values = _.chain(data).pluck("a").unique().compact().value();

Upvotes: 4

Related Questions