Reputation: 5762
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
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
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
Reputation: 920
One liner option:
[...new Set(a.map(Object.keys).reduce((a, b) => a.concat(b)))];
Upvotes: 0
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
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
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
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
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
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