Home > Blockchain >  How, from an array of objects, does one group, merge and aggregate values, each task by one or more
How, from an array of objects, does one group, merge and aggregate values, each task by one or more

Time:05-30

I have an array of objects as below.

I would like to group those with the same bank, gender, age, and state together.

I'd like to sum their depositAmount and withdrawalAmount together, respectively, and count each group as well. (user is excluded in the output)

Example Array

[{
    "bank": "bank1",
    "user": "u1",
    "depositAmount": 12,
    "withdrawalAmount": 33,
    "gender": "male",
    "age": 38,
    "state": "Arizona"
},
{
    "bank": "bank1",
    "user": "u2",
    "depositAmount": 25,
    "withdrawalAmount": 44,
    "gender": "male",
    "age": 38,
    "state": "Arizona"
},
{
    "bank": "bank2",
    "user": "u3",
    "depositAmount": 10,
    "withdrawalAmount": 0,
    "gender": "male",
    "age": 38,
    "state": "Florida"
}]

Expected Output

[{  
    "bank": "bank1"
    "depositAmount": 27,
    "withdrawalAmount": 77,
    "gender": "male",
    "age": 38,
    "state": "Arizona"
    "count": 2
},
{  
    "bank": "bank2"
    "depositAmount": 10,
    "withdrawalAmount": 0,
    "gender": "male",
    "age": 38,
    "state": "Florida"
    "count": 1
}]

CodePudding user response:

A generic solution to this problem was to implement a configurable reducer-function for the ... "It groups, merges and aggregates" task.

In order to cover the OP's requirements, one provides an accordingly tailored custom collector-object as the reduce-method's initial value.

The generic reducer expects to get provided a createKey, a createMerger and an aggregate function as well as a Map based lookup and an empty result-array where the latter, once the reduce task has been run, will hold all the grouped/merged and aggregated objects.

As for the OP's specific requirements the provided functions are ...

  • OP ...

    "I would like to group those with the same bank, gender, age, and state together."

    • createKey: ({ bank, gender, age, state }) => [bank, gender, age, state].join('_')
  • OP ...

    "I'd like to sum their depositAmount and withdrawalAmount together, respectively, and count each group as well. (user is excluded in the output)."

    • createMerger: ({ bank, gender, age, state }) => ({ bank, gender, age, state, count: 0, depositAmount: 0, withdrawalAmount: 0 })

    • aggregate: (merger, { depositAmount, withdrawalAmount }) => { merger.count; merger.depositAmount = depositAmount; merger.withdrawalAmount = withdrawalAmount; }

function groupMergeAndAggregateGenerically(collector, item) {
  const {
    createKey, createMerger, aggregate,
    lookup, result = [],
  } = collector;

  const key = createKey(item);
  let merger = lookup.get(key) ?? null;

  if (merger === null) {
    merger = createMerger(item);

    lookup.set(key, merger);
    result.push(merger);
  }
  aggregate(merger, item);

  return collector;
}

const sampleData = [{
  "bank": "bank1",
  "user": "u1",
  "depositAmount": 12,
  "withdrawalAmount": 33,
  "gender": "male",
  "age": 38,
  "state": "Arizona"
}, {
  "bank": "bank1",
  "user": "u2",
  "depositAmount": 25,
  "withdrawalAmount": 44,
  "gender": "male",
  "age": 38,
  "state": "Arizona"
}, {
  "bank": "bank2",
  "user": "u3",
  "depositAmount": 10,
  "withdrawalAmount": 0,
  "gender": "male",
  "age": 38,
  "state": "Florida"
}];

// OP: I would like to group those with the same
// `bank`, `gender`, `age`, and `state` together.
const createKey = ({ bank, gender, age, state }) =>
  [bank, gender, age, state].join('_');

// OP: I'd like to sum their `depositAmount` and
// `withdrawalAmount` together, respectively, and
// `count` each group as well. (`user` is excluded in the output).
const createMerger = ({ bank, gender, age, state }) => ({
  bank, gender, age, state, count: 0, depositAmount: 0, withdrawalAmount: 0,
});
const aggregate = (merger, { depositAmount, withdrawalAmount }) => {
    merger.count;
  merger.depositAmount  = depositAmount;
  merger.withdrawalAmount  = withdrawalAmount;
};

const { result: mergedData } = sampleData
  .reduce(groupMergeAndAggregateGenerically, {
    createKey,
    createMerger,
    aggregate,
    lookup: new Map,
    result: [],      
  });

console.log({ mergedData });
.as-console-wrapper { min-height: 100%!important; top: 0; }

  • Related