Andurit
Andurit

Reputation: 5762

Get all unique object properties from array of objects

Let's imagine I have an array of objects e.g.

 [{
    "firstName": "John",
    "lastName": "Doe"
 }, {
    "firstName": "Anna",
    "car": true
 }, {
    "firstName": "Peter",
    "lastName": "Jones"
 }]

I want to get all the unique property names from this array of objects, so the result will be:

[firstName, lastName, car]

How can I do it:

I can imagine that it's possible to do this with something like this:

function getPropertiesNames(obj){
  var arr = [];
  for(var name in obj) {
    if(arr.indexOf(name) != -1) arr.push(name);
  }
 return arr;
} 

Why I need it:

I will have to make a table of multiple objects. Because each object can be a bit different I need unique property names. However I am going to do it in angularJS so it's kind of a bad option for me to once use loop to get property names for <th> and once again use loop with <tr ng-repeat></tr> to display values.

What i want:

Is there some option to get all unique property names from an array of objects without iterating it? Maybe some lodash or build in JS function which I don't know?

Upvotes: 17

Views: 15383

Answers (9)

adiga
adiga

Reputation: 35259

You can use Object.assign() and spread syntax to merge the array of objects to a single object. Then get the keys from the merged object:

Object.keys(Object.assign({}, ...array)) 

Here's a snippet:

const array = [{firstName:"John",lastName:"Doe"},{firstName:"Anna",car:true},{firstName:"Peter",lastName:"Jones"}],
      unique = Object.keys(Object.assign({}, ...array))

console.log(unique)


Another option is to use Object.keys as callback to flatMap. This returns an array of all the keys. Then, create a Set to get unique keys and use Array.from() to convert the set to an array.

const keys = input.flatMap(Object.keys),
      unique = Array.from(new Set(keys));

Here's a working snippet:

const input=[{firstName:"John",lastName:"Doe"},{firstName:"Anna",car:true},{firstName:"Peter",lastName:"Jones"}],
      unique = Array.from(new Set(input.flatMap(Object.keys)));

console.log(unique)

If flatMap is not supported, you can use

const keys = [].concat(...input.map(Object.keys)),

Upvotes: 5

mplungjan
mplungjan

Reputation: 178401

Alternative using flat

const arr = 
[{
    "firstName": "John",
    "lastName": "Doe"
 }, {
    "firstName": "Anna",
    "car": true
 }, {
    "firstName": "Peter",
    "lastName": "Jones"
 }].map(obj => Object.getOwnPropertyNames(obj)).flat()
const s = [...new Set(arr)]
console.log(s) 

Upvotes: 2

The Witness
The Witness

Reputation: 920

One liner option:

[...new Set(a.map(Object.keys).reduce((a, b) => a.concat(b)))];

Upvotes: 0

Ved
Ved

Reputation: 12113

My solution without any library.

var array = [{
  "firstName": "John",
  "lastName": "Doe"
}, {
  "firstName": "Anna",
  "car": true
}, {
  "firstName": "Peter",
  "lastName": "Jones"
}];

var arr = [],merged,uniqArray;

array.forEach(function(val){ //Getting all properties
   arr.push(Object.keys(val))
 });

merged = [].concat.apply([], arr);//Merging all array to single array

merged.forEach(function(val){
  if(uniqArray.indexOf(val)== -1){// Getting uniqe values
   uniqArray.push(val)
}})

RESULT

["firstName", "lastName", "car"]

Upvotes: 2

Rachid
Rachid

Reputation: 76

You can use this:

var result = [];
array.reduce( function(pre, item) {
    Object.keys(item).forEach(function(i){
        if (result.indexOf(i) === -1){
            result.push(i);
        }
    });
});

var array = [{
  "firstName": "John",
  "lastName": "Doe"
}, {
  "firstName": "Anna",
  "car": true
}, {
  "firstName": "Peter",
  "lastName": "Jones"
}];

var result = [];
array.reduce( function(pre, item) {
    Object.keys(item).forEach(function(i){
        if (result.indexOf(i) === -1){
            result.push(i);
        }
    });
});

console.log(result);

Upvotes: 2

Dhananjaya Kuppu
Dhananjaya Kuppu

Reputation: 1322

You may also try this:

var source = [{
"firstName": "John",
"lastName": "Doe"
 }, {
"firstName": "Anna",
"car": true
 }, {
"firstName": "Peter",
"lastName": "Jones"
 }];

uniq(source);

function uniq(source){
   var result = source.reduce(function(p, c) {

     Object.keys(c).forEach(function(key) {
         p[key] = true;
     });

     return p;
    }, {});

    return Object.keys(result);
}

Upvotes: 2

user3297291
user3297291

Reputation: 23397

A solution using only:

var data = [{
  "firstName": "John",
  "lastName": "Doe"
}, {
  "firstName": "Anna",
  "car": true
}, {
  "firstName": "Peter",
  "lastName": "Jones"
}];

var uniqueKeys = Object.keys(data.reduce(function(result, obj) {
  return Object.assign(result, obj);
}, {}))

console.log(uniqueKeys);

Upvotes: 25

Tholle
Tholle

Reputation: 112917

I don't think you can get away from checking each key in each object. You could accomplish it with e.g reduce:

var result = _.reduce(array, function(memory, obj) {
  for (var key in obj) {
    if(memory.indexOf(key) === -1) memory.push(key)
  }
  return memory;
}, []);

var array = [{
  "firstName": "John",
  "lastName": "Doe"
}, {
  "firstName": "Anna",
  "car": true
}, {
  "firstName": "Peter",
  "lastName": "Jones"
}];

var result = _.reduce(array, function(memory, obj) {
  for (var key in obj) {
    if(memory.indexOf(key) === -1) memory.push(key)
  }
  return memory;
}, []);

console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.15.0/lodash.min.js"></script>

Alternatively, you could store the keys in a new object, and just extract the keys:

var temp = _.reduce(array, function(memory, obj) {
  for (var key in obj) {
    memory[key] = null;
  }
  return memory;
}, {});
var result = Object.keys(temp);

var array = [{
  "firstName": "John",
  "lastName": "Doe"
}, {
  "firstName": "Anna",
  "car": true
}, {
  "firstName": "Peter",
  "lastName": "Jones"
}];

var temp = _.reduce(array, function(memory, obj) {
  for (var key in obj) {
    memory[key] = null;
  }
  return memory;
}, {});
var result = Object.keys(temp);

console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.15.0/lodash.min.js"></script>

Upvotes: 3

Nenad Vracar
Nenad Vracar

Reputation: 122145

You could use map() and keys() to return keys of each object and then union() and flatten()

var data = [{
  "firstName": "John",
  "lastName": "Doe"
}, {
  "firstName": "Anna",
  "car": true
}, {
  "firstName": "Peter",
  "lastName": "Jones"
}]

var result = _.union(_.flatten(_.map(data, (e) => _.keys(e))));
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.15.0/lodash.min.js"></script>

Upvotes: 4

Related Questions