Reputation: 27852
I have an input array of objects, which each object has the following format:
{
titleID: string,
titleName: string,
1af23_red: number,
45ua6_blue: number
}
What I know is that:
In every object, there will be always the keys titleID
and titleName
and then I will have several keys that have the format number_string
.
The titleID
and titleName
values will be different among the different objects
The rest of the keys (1af23_red, 45ua6_blue, etc) will be the same in all objects and they will all have the same format 'id_name' So, if the first object has 1af23_red and 45ua6_blue as keys, all the rest will also have just those keys.
The type of array that I want back has the following format:
{
color: {
id
name
},
data: Array<
{
title: {
id
name
},
rating
}
>
}
So, example of input:
[
{
titleId: 'a',
titleName: 'atitle',
'1af_red': 50
'ba2_blue': 40
},
{
titleId: 'b',
titleName: 'btitle',
'1af_red': 30
'ba2_blue': null
},
{
titleId: 'c',
titleName: 'ctitle',
'1af_red': null
'ba2_blue': 10
}
]
I would expect back:
[
{
color: {
id: '1af',
name: 'red'
},
data: [
{
title: {
id: 'a',
name: 'atitle',
},
rating: 50
},
{
title: {
id: 'b',
name: 'btitle',
},
rating: 30
},
{
title: {
id: 'c',
name: 'ctitle',
},
rating: null
}
]
},
{
color: {
id: 'ba2',
name: 'blue'
},
data: [
{
title: {
id: 'a',
name: 'atitle',
},
rating: 40
},
{
title: {
id: 'b',
name: 'btitle',
},
rating: null
},
{
title: {
id: 'c',
name: 'ctitle',
},
rating: 10
}
]
}
]
I have tried doing this conversion with map and reduce but I am stuck. Is there an easy way to accomplish this?
Upvotes: 1
Views: 339
Reputation: 3297
You could try that
let elements = [
{
titleId: 'a',
titleName: 'atitle',
'1af_red': 50,
'ba2_blue': 40
},
{
titleId: 'b',
titleName: 'btitle',
'1af_red': 30,
'ba2_blue': null
},
{
titleId: 'c',
titleName: 'ctitle',
'1af_red': null,
'ba2_blue': 10
}
]
let colors = []
let result = []
elements.forEach(currElem => {
for(let attr in currElem){
if(attr != "titleId" && attr != "titleName"){
let color = attr.split("_")
if(!colors.some(currColor => {return currColor == color[1]})){
colors.push({
"id": color[0],
"name": color[1]
})
}
}
}
})
colors.forEach(currColor => {
result.push({
"color" : currColor,
"data": []
})
elements.forEach(currElement => {
for(let attr in currElement){
let color = []
if(attr != "titleId" && attr != "titleName"){
color = attr.split("_")
if(color[1] == currColor.name){
for(let i=0; i<result.length;i++){
if(result[i].color.name == color[1]){
result[i].data.push({
"title" : {
"id": currElement.titleId,
"name": currElement.titleName
},
"rating":currElement[attr]
})
break
}
}
}
}
}
})
})
console.log(result)
Upvotes: 1
Reputation: 1180
Here you go.
Brief logic : Getting all the keys from the object at 0th index from data array. Looping over the keys, if key contains '_', pick the key, break it to form id and name pair, then map over all the data objects, get the score for that key and append it to the object with id and name values. Finally append this object to result array. Doing this for all the keys which contains '_'.
const data = [
{
titleId: 'a',
titleName: 'atitle',
'1af_red': 50,
'ba2_blue': 40
},
{
titleId: 'b',
titleName: 'btitle',
'1af_red': 30,
'ba2_blue': null
},
{
titleId: 'c',
titleName: 'ctitle',
'1af_red': null,
'ba2_blue': 10
}
];
const keys = Object.keys(data[0]);
const result = []
keys.map(key=> {
if(key.indexOf('_')!==-1){
const item = {}
const keyData = key.split('_')
item.color = {
id : keyData[0],
name : keyData[1]
}
item.data = []
data.map(obj => {
const newObj = {}
newObj.title = {
id : obj.titleId,
name : obj.titleName
}
newObj.rating = obj[key];
item.data.push(newObj);
});
result.push(item);
}
});
console.log(result);
Upvotes: 4