I have an array of objects, and I want to convert them to consume the data in a chart. Someone recommends using lodash, but I don't want to use any libraries. So here is the example of the array:
const items = [
{
priceChangeType: 'CL',
hierarchy: {
department: {
description: 'TEXTILES',
},
},
},
{
priceChangeType: 'PM',
hierarchy: {
department: {
description: 'CLOTHES',
},
},
},
{
priceChangeType: 'CL',
hierarchy: {
department: {
description: 'TEXTILES',
},
},
},
{
priceChangeType: 'CL',
hierarchy: {
department: {
description: 'CLOTHES',
},
},
},
{
priceChangeType: 'PM',
hierarchy: {
department: {
description: 'BATH',
},
},
},
{
priceChangeType: 'PM',
hierarchy: {
department: {
description: 'TOOLS',
},
},
},
{
priceChangeType: 'CL',
hierarchy: {
department: {
description: 'TOOLS',
},
},
},
{
priceChangeType: 'CL',
hierarchy: {
department: {
description: 'TOOLS',
},
},
},
]
And I want an output like this, and this is the format needed for the chart.
const data = [
{name: 'TOOLS', PM: 1, CL: 2},
{name: 'CLOTHES', PM: 1, CL: 1},
{name: 'TEXTILES', PM: 0, CL: 2},
{name: 'BATH', PM: 1, CL: 0},
]
This is the furthest I've come, but only the total counts.
const totalPriceChangesType = Object.entries(items.reduce((r, v, i, a, k = v.priceChangeType) => ((r[k] || (r[k] = [])).push(v), r), {})).map(
([key, value]) => ({
[key] : value.length,
}),
)
CodePudding user response:
Maybe this example can help you?
const items = [{
priceChangeType: "CL",
hierarchy: {
department: {
description: "TEXTILES"
}
}
},
{
priceChangeType: "PM",
hierarchy: {
department: {
description: "CLOTHES"
}
}
},
{
priceChangeType: "CL",
hierarchy: {
department: {
description: "TEXTILES"
}
}
},
{
priceChangeType: "CL",
hierarchy: {
department: {
description: "CLOTHES"
}
}
},
{
priceChangeType: "PM",
hierarchy: {
department: {
description: "BATH"
}
}
},
{
priceChangeType: "PM",
hierarchy: {
department: {
description: "TOOLS"
}
}
},
{
priceChangeType: "CL",
hierarchy: {
department: {
description: "TOOLS"
}
}
},
{
priceChangeType: "CL",
hierarchy: {
department: {
description: "TOOLS"
}
}
}
];
// collect all possible PM, CL, etc. (example: {PM:0, CL:0})
const priceChangeTypes = items.reduce((acc, item) => (acc[item.priceChangeType] = 0, acc), {});
const total = Object.values(items.reduce((acc, item) => {
const descriprion = item.hierarchy.department.description;
const priceChangeType = item.priceChangeType;
// create a new base object {name: "{description}", PM:0, CL:0, ...}
if (!acc[descriprion]) acc[descriprion] = {
name: descriprion,
...priceChangeTypes
};
acc[descriprion][priceChangeType] ;
return acc;
}, {}));
console.log(total);
CodePudding user response:
Logic
- Generate unique types from the
itemsarray usingArray.mapandSet - Reduce the
itemsarray against the name and type - Add the missing type to individual nodes in the
outputarray
const items = [{priceChangeType: 'CL',hierarchy: {department: {description: 'TEXTILES'}}},{priceChangeType: 'PM',hierarchy: {department: {description: 'CLOTHES'}}},{priceChangeType: 'CL',hierarchy: {department: {description: 'TEXTILES'}}},{priceChangeType: 'CL',hierarchy: {department: {description: 'CLOTHES'}}},{priceChangeType: 'PM',hierarchy: {department: {description: 'BATH'}}},{priceChangeType: 'PM',hierarchy: {department: {description: 'TOOLS'}}},{priceChangeType: 'CL',hierarchy: {department: {description: 'TOOLS'}}},{priceChangeType: 'CL',hierarchy: {department: {description: 'TOOLS'}}}];
// Generate unique types
const types = Array.from(new Set(items.map(item => item.priceChangeType)));
// Reduce the items array against the name and type
const output = items.reduce((acc, curr, index, array, name = curr.hierarchy.department.description, type = curr.priceChangeType) => {
acc[name] = acc[name] || {};
acc[name][type] = acc[name][type] || 1;
return acc;
}, {});
// Add the missing type to each object in output
Object.entries(output).forEach(([key, value]) => types.forEach(type => output[key][type] = output[key][type] || 0))
console.log(output);
CodePudding user response:
You can create an object (priceChangeTypes) of all the priceChangeType initialized to 0 by mapping the array to [priceChangeType, 0] pairs, and using Object.fromEntries().
Then reduce the original array to a Map. For each new hierarchy.department.description create an entry in the Map by spreading priceChangeTypes to a new object, and increment the relevant priceChangeType.
Convert back to an array using Array.from().
const items = [{priceChangeType: 'CL',hierarchy: {department: {description: 'TEXTILES'}}},{priceChangeType: 'PM',hierarchy: {department: {description: 'CLOTHES'}}},{priceChangeType: 'CL',hierarchy: {department: {description: 'TEXTILES'}}},{priceChangeType: 'CL',hierarchy: {department: {description: 'CLOTHES'}}},{priceChangeType: 'PM',hierarchy: {department: {description: 'BATH'}}},{priceChangeType: 'PM',hierarchy: {department: {description: 'TOOLS'}}},{priceChangeType: 'CL',hierarchy: {department: {description: 'TOOLS'}}},{priceChangeType: 'CL',hierarchy: {department: {description: 'TOOLS'}}}]
// Create an initialized counts object = { CL: 0, PM: 0 }
const priceChangeTypes = Object.fromEntries(items.map(o => [o.priceChangeType, 0]))
const result = Array.from(
items.reduce((acc, o) => {
const key = o.hierarchy.department.description
// initialize the object for the current key if needed
if(!acc.has(key)) acc.set(key, { ...priceChangeTypes })
// increment the relevant priceChangeType
acc.get(key)[o.priceChangeType] = 1
return acc
}, new Map()),
([names, values]) => ({ name, ...values }) // convert to an array
)
console.log(result)
