Small helper to get SHALLOW copy of obj
where prop
ELIMINATED
const rmProp = (obj, prop) => ( (({[prop]:_, ...rest})=>rest)(obj) )
Group Array by key. Root keys of a resulting array is value of specified key.
type | name | description |
---|---|---|
{Array} | src | The source array |
{String} | key | The by key to group by |
{Object} | return | Object with grouped objects as values |
const grpBy = (src, key) => src.reduce((a, e) => (
(a[e[key]] = a[e[key]] || []).push(rmProp(e, key)), a
), {});
Collapse array of object if it consists of only object with single value. Replace it by the rest value.
const blowObj = obj => Array.isArray(obj) && obj.length === 1 && Object.values(obj[0]).length === 1 ? Object.values(obj[0])[0] : obj;
Recursive grouping with list of keys. keyList
may be an array
of key names or comma separated list of key names whom UNIQUE values will
becomes the keys of the resulting object.
const grpByReal = function (src, keyList) {
const [key, ...rest] = Array.isArray(keyList) ? keyList : String(keyList).trim().split(/\s*,\s*/);
const res = key ? grpBy(src, key) : [...src];
if (rest.length) {
for (const k in res) {
res[k] = grpByReal(res[k], rest)
}
} else {
for (const k in res) {
res[k] = blowObj(res[k])
}
}
return res;
}
/******************** DEMO ***********************************************/
const data = [
{ Phase: "Phase 1", Step: "Step 1", Task: "Task 1", Value: "5" },
{ Phase: "Phase 1", Step: "Step 1", Task: "Task 2", Value: "10" },
{ Phase: "Phase 1", Step: "Step 2", Task: "Task 1", Value: "15" },
{ Phase: "Phase 1", Step: "Step 2", Task: "Task 2", Value: "20" },
{ Phase: "Phase 2", Step: "Step 1", Task: "Task 1", Value: "25" },
{ Phase: "Phase 2", Step: "Step 1", Task: "Task 2", Value: "30" },
{ Phase: "Phase 2", Step: "Step 2", Task: "Task 1", Value: "35" },
{ Phase: "Phase 2", Step: "Step 2", Task: "Task 2", Value: "40" }
];
console.log( JSON.stringify( grpByReal (data, 'Phase, Step, Task'), null, 2 ) );