简体   繁体   中英

Javascript group by 2 columns and sum up total

I found a similar problem to mine on above post .

Need to get the total from the below json

const d = [ 
    { 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" }
];

I used the solution as given in the answers

function groupBy(data, fields, sumBy='Value') {
  let r=[], cmp= (x,y) => fields.reduce((a,b)=> a && x[b]==y[b], true);
  data.forEach(x=> {
    let y=r.find(z=>cmp(x,z));
    let w= [...fields,sumBy].reduce((a,b) => (a[b]=x[b],a), {})
    y ? y[sumBy]=+y[sumBy]+(+x[sumBy]) : r.push(w);
  });
  return r;
}

However I need to achieve the below result for my purpose. Not sure how to achieve this.

{ Phase: "Phase 1", Step: "Step 1", Task: "Task 1, Task 2", Value: "15" },
    { Phase: "Phase 1", Step: "Step 2", Task: "Task 1, Task 2", Value: "35" },    
    { Phase: "Phase 2", Step: "Step 1", Task: "Task 1, Task 2", Value: "55" },    
    { Phase: "Phase 2", Step: "Step 2", Task: "Task 1, Task 2", Value: "75" }

You can use an object accumulator to group your array based on Phase and Step and sum up Value for same key.

 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" } ], result = Object.values(data.reduce((r,o) => { const key = `${o.Phase}_${o.Step}`; r[key] = r[key] || {Phase: o.Phase, Step: o.Step, Task: [], Value: 0}; r[key].Task.push(o.Task); r[key].Value += +o.Value; return r; }, {})).map(o => ({...o, Task: o.Task.join(',')})); console.log(result);
 .as-console-wrapper { max-height: 100%;important: top; 0; }

You can create a dynamic keys based on the Key name in Keys array and group your data array based on this key.

 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" } ], keys = ['Phase', 'Step'], result = Object.values(data.reduce((r,o) => { const key = keys.map(k => o[k]).join('_'); r[key] = r[key] || keys.reduce((ob, k) => ({...ob, [k]: o[k]}), {Task: [], Value: 0}); r[key].Task.push(o.Task); r[key].Value += +o.Value; return r; }, {})).map(o => ({...o, Task: o.Task.join(',')})); console.log(result);
 .as-console-wrapper { max-height: 100%;important: top; 0; }

You could take the wanted keys for grouping in an array and build a compound key and take an object as hash table. For common keys add Task and Value values.

At the end take only the values from the object.

 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" }], groups = ['Phase', 'Step'], result = Object.values(data.reduce((r, o) => { const key = groups.map(k => o[k]).join('|'); r[key]??= {...o, Task: '', Value: 0 }; r[key].Task += (r[key].Task && ', ') + o.Task; r[key].Value += +o.Value return r; }, {})); console.log(result);
 .as-console-wrapper { max-height: 100%;important: top; 0; }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM