I nave an array:
const arr = [
{ name: "aa", type: "total", count: 28394 },
{ name: "aa", type: "featured", count: 4 },
{ name: "aa", type: "noAnswers", count: 5816 },
{ name: "ba", type: "total", count: 148902 },
{ name: "ba", type: "featured", count: 13 },
{ name: "ba", type: "noAnswers", count: 32527 },
{ name: "cc", type: "total", count: 120531 },
{ name: "cc", type: "featured", count: 6 },
{ name: "cc", type: "noAnswers", count: 24170 }
];
const arrResult = [
{ name: "aa", total: 28394, featured: 4, noAnswers: 5816 },
{ name: "ba", total: 148902, featured: 13, noAnswers: 32527 },
{ name: "cc", total: 120531, featured: 6, noAnswers: 24170 }
];
I e up with this code:
let output = [];
const unique = [...new Set(arr.map(item => item.name))];
for(const key of unique) {
let result = arr.filter(x => {
return x.name === key;
});
output.push({
name: key,
// need to get the rest of the properties here
// total
// featured
// noAnswers
});
}
The only one thing I can not figure out is how to get the property names. Any ideas?
I nave an array:
const arr = [
{ name: "aa", type: "total", count: 28394 },
{ name: "aa", type: "featured", count: 4 },
{ name: "aa", type: "noAnswers", count: 5816 },
{ name: "ba", type: "total", count: 148902 },
{ name: "ba", type: "featured", count: 13 },
{ name: "ba", type: "noAnswers", count: 32527 },
{ name: "cc", type: "total", count: 120531 },
{ name: "cc", type: "featured", count: 6 },
{ name: "cc", type: "noAnswers", count: 24170 }
];
const arrResult = [
{ name: "aa", total: 28394, featured: 4, noAnswers: 5816 },
{ name: "ba", total: 148902, featured: 13, noAnswers: 32527 },
{ name: "cc", total: 120531, featured: 6, noAnswers: 24170 }
];
I e up with this code:
let output = [];
const unique = [...new Set(arr.map(item => item.name))];
for(const key of unique) {
let result = arr.filter(x => {
return x.name === key;
});
output.push({
name: key,
// need to get the rest of the properties here
// total
// featured
// noAnswers
});
}
The only one thing I can not figure out is how to get the property names. Any ideas?
Share Improve this question asked Jan 17, 2019 at 6:27 SerginoSergino 10.9k37 gold badges107 silver badges181 bronze badges6 Answers
Reset to default 5You can try something like this:
Idea:
- Create a hashMap so you can group objects via
name
. - Then, add necessary properties to this group.
- Finally, loop over keys and create final object with name property added back.
const arr = [ { name: "aa", type: "total", count: 28394 }, { name: "aa", type: "featured", count: 4 }, { name: "aa", type: "noAnswers", count: 5816 }, { name: "ba", type: "total", count: 148902 }, { name: "ba", type: "featured", count: 13 }, { name: "ba", type: "noAnswers", count: 32527 }, { name: "cc", type: "total", count: 120531 }, { name: "cc", type: "featured", count: 6 }, { name: "cc", type: "noAnswers", count: 24170 } ];
const hashMap = arr.reduce((acc, item) => {
acc[item.name] = acc[item.name] || {};
acc[item.name][item.type] = item.count;
return acc;
}, {});
const result = Object.keys(hashMap).map((name) => Object.assign({}, {name}, hashMap[name] ));
console.log(result)
Working:
What I'm doing is I'm creating a new object for every new name
. So, this: acc[item.name] = acc[item.name] || {};
checks if the entry is unavailable or not.
- If unavailable, return a new object.
- If available, return same object's reference.
So for any given name, you will only refer to same object.
Now this: acc[item.name][item.type] = item.count
sets the properties. As we are referring to same object, you are setting property in one place. So if you have duplicate entries, say
[
{ name: "aa", type: "total", count: 28394 },
{ name: "aa", type: "total", count: 123},
]
output will have total: 123
instead.
So, at the end, you have a structure like:
{
aa: {
total: <something>,
feature: <something>,
...
}
}
Now all you have to do is merge the name in this object and return the value. You can also create the object with name
property as default (as done by adiga). Thats something I didn't think while answering. So crediting instead of answering.
You can use reduce
and destructuring like this:
The idea is to create an object with key
as the name
property and value as the final objects you need in the output. So, that you can simply use Object.values
to get the final array:
const arr=[{name:"aa",type:"total",count:28394},{name:"aa",type:"featured",count:4},{name:"aa",type:"noAnswers",count:5816},{name:"ba",type:"total",count:148902},{name:"ba",type:"featured",count:13},{name:"ba",type:"noAnswers",count:32527},{name:"cc",type:"total",count:120531},{name:"cc",type:"featured",count:6},{name:"cc",type:"noAnswers",count:24170}];
const merged = arr.reduce((acc,{name,type,count}) =>
((acc[name] = acc[name] || {name})[type] = count, acc)
,{})
console.log(Object.values(merged))
This is equivalent to :
const arr=[{name:"aa",type:"total",count:28394},{name:"aa",type:"featured",count:4},{name:"aa",type:"noAnswers",count:5816},{name:"ba",type:"total",count:148902},{name:"ba",type:"featured",count:13},{name:"ba",type:"noAnswers",count:32527},{name:"cc",type:"total",count:120531},{name:"cc",type:"featured",count:6},{name:"cc",type:"noAnswers",count:24170}];
/* Our goal is to create a merged object like this:
{
"aa": {
"name": "aa",
"total": 28394,
"featured": 4,
"noAnswers": 5816
},
"ba": {
"name": "ba",
"total": 148902,
....
},
"cc": {
"name": "cc",
......
}
}
The advantage of using object accumulator is we can access it like this: acc[name]
*/
const merged = arr.reduce((acc, {name,type,count} /*Destructuring*/) => {
/* if the accumulator doesn't have the current "name" key,
create new object
else use the existing one;
{name} is same as {name: name}
*/
acc[name] = acc[name] || {name};
/* To the inner object,
add a key with the "type" value and assign it to "count" value
*/
acc[name][type] = count;
// return the accumulator
return acc;
}, {})
// use Object.values to get the value part of the merged obejct into an array
console.log(Object.values(merged))
var op = {name : key};
for(i=0; i < result.length; i++){
op[result[i].type] = result[i].count;
}
output.push(op);
just adding this will work fine. However your code is not the most efficient. Hashing based on name will make it faster
const arr = [
{ name: "aa", type: "total", count: 28394 },
{ name: "aa", type: "featured", count: 4 },
{ name: "aa", type: "noAnswers", count: 5816 },
{ name: "ba", type: "total", count: 148902 },
{ name: "ba", type: "featured", count: 13 },
{ name: "ba", type: "noAnswers", count: 32527 },
{ name: "cc", type: "total", count: 120531 },
{ name: "cc", type: "featured", count: 6 },
{ name: "cc", type: "noAnswers", count: 24170 }
];
let output = [];
const unique = [...new Set(arr.map(item => item.name))];
for(const key of unique) {
let result = arr.filter(x => {
return x.name === key;
});
var op = {name : key};
for(i=0; i < result.length; i++){
op[result[i].type] = result[i].count;
}
output.push(op);
}
console.log(output);
The following is the most efficient way of doing it :
const arr = [
{ name: "aa", type: "total", count: 28394 },
{ name: "aa", type: "featured", count: 4 },
{ name: "aa", type: "noAnswers", count: 5816 },
{ name: "ba", type: "total", count: 148902 },
{ name: "ba", type: "featured", count: 13 },
{ name: "ba", type: "noAnswers", count: 32527 },
{ name: "cc", type: "total", count: 120531 },
{ name: "cc", type: "featured", count: 6 },
{ name: "cc", type: "noAnswers", count: 24170 }
];
var hash = {};
var result = [];
for(var i=0; i < arr.length; i++){
if(!arr[i].name in hash)
hash[arr[i].name] = {}
let temp = {};
temp[arr[i].type] = arr[i].count;
hash[arr[i].name] = Object.assign(temp, hash[arr[i].name]);
}
for(var key in hash)
result.push({name : key, ...hash[key]})
console.log(result)
You can use find
operator of javascript to grab the desired row from arrResult
Change your code like below-
for(const key of unique) {
let result = arr.filter(x => {
return x.name === key;
});
var currResult = arrResult.find(x => x.name == key);
output.push({
name: key,
// need to get the rest of the properties here
total: currResult.total,
featured: currResult.featured,
noAnswers: currResult.noAnswers
});
}
JSFiddle: https://jsfiddle/ashhaq12345/z8royg5w/
const arr = [
{ name: "aa", type: "total", count: 28394 },
{ name: "aa", type: "featured", count: 4 },
{ name: "aa", type: "noAnswers", count: 5816 },
{ name: "ba", type: "total", count: 148902 },
{ name: "ba", type: "featured", count: 13 },
{ name: "ba", type: "noAnswers", count: 32527 },
{ name: "cc", type: "total", count: 120531 },
{ name: "cc", type: "featured", count: 6 },
{ name: "cc", type: "noAnswers", count: 24170 }
];
const names = [...new Set(arr.map(item => item.name))]
const output = {};
names.forEach(name => {output[name] = {}});
arr.forEach(item => {
output[item.name][item.type] = item.count
});
const result = Object.entries(output).map(([name, rest]) => ({name, ...rest}))
console.log(result);
const arrResult = [
{ name: "aa", total: 28394, featured: 4, noAnswers: 5816 },
{ name: "ba", total: 148902, featured: 13, noAnswers: 32527 },
{ name: "cc", total: 120531, featured: 6, noAnswers: 24170 }
];
You can simply use for loop to iterate over your array and take a temp array and take map and fill the map using required data and then push your map into temp array like following.
const arr = [
{ name: "aa", type: "total", count: 28394 },
{ name: "aa", type: "featured", count: 4 },
{ name: "aa", type: "noAnswers", count: 5816 },
{ name: "ba", type: "total", count: 148902 },
{ name: "ba", type: "featured", count: 13 },
{ name: "ba", type: "noAnswers", count: 32527 },
{ name: "cc", type: "total", count: 120531 },
{ name: "cc", type: "featured", count: 6 },
{ name: "cc", type: "noAnswers", count: 24170 }
];
let result = [];
for( var i = 0; i < arr.length; i++)
{
let data = {};
if( arr[i].type == 'total')
{
data.name = arr[i].name;
data.total = arr[i].count;
data.featured = arr[i+1].count;
data.noAnswers = arr[i+2].count;
result.push(data);
}
}
console.log(result);