Finding unique values in an array My objective is to make an array of unique keys from a list of objects.

Example:

Input:

var input = [{"a":1, "b":2}, {"a":3, "c":4}, {"a":5}]


Output:


[ "a", "b", "c" ]



Current approach:

var outputObj={};
input.map( function( obj ) {  
    Object.keys( obj ).map( function(key) { 
        outputObj[key] = 1;
    })  
});
// output obj is now { a : 1, b: 1, c: 1 }
var output = Object.keys( outputObj );


This works, but it just smells funny, partly because the map function is relying on side-effects. Is there a better way to do this?

In Java, I would create a java.util.Set and simply add all keys to it.
You could clean it up a bit by using reduce and forEach instead of map (especially as you don't need map's return value, but are just using it as an iterator)

function uniqueKeys(objects) {
  var keys = objects.reduce(function (collector, obj) {
    Object.keys(obj).forEach(function (key) {
      collector[key] = true;
    });
    return collector;
  }, {});
  return Object.keys(keys);
}


Alternatively, you could combine all the objects, and then use Object.keys on the result. Just be careful, as extend-type functions usually work on the passed objects directly (as the one below does), rather than returning a new object, so pass an empty object to use as collector:

function extend(target, source) {
  var key;
  for(key in source) {
    target[key] = source[key];
  }
  return target;
}

function uniqueKeys(objects) {
  var combined = objects.reduce(function (target, obj) {
    extend(target, obj);
    return target;
  }, {});
  return Object.keys(combined);
}


If you've got an extend function that takes an arbitrary number of arguments, you could do something like

function uniqueKeys(objects) {
  var collector = {};
  extend.apply(null, [collector].concat(objects));
  return Object.keys(collector);
}


Here are demos of each one