如何从一组对象中,通过一个或多个不同的 属性-names / object-keys 进行一组,合并和聚合值,每个任务?

How, from an array of objects, does one group, merge and aggregate values, each task by one or more different property-names / object-keys?

我有一个对象数组如下。

我想将具有相同 bankgenderagestate 的那些组合在一起。

我想分别求和他们的depositAmountwithdrawalAmount,每个计数组也是如此。 (输出中排除了user

示例数组

[{
    "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"
}]

预期输出

[{  
    "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
}]

此问题的通用解决方案是为...实施可配置的 reducer-function “它分组、合并和聚合”任务。

为了满足 OP 的要求,提供了相应定制的自定义 collector-object 作为 reduce-method's initial value

通用减速器期望得到一个 createKey、一个 createMerger 和一个 aggregate 函数以及一个基于 Maplookup 和一个空 result-array 其中后者,一旦 reduce 任务已经 运行,将保存所有 grouped/merged 和聚合对象。

至于OP的具体要求,提供的功能是...

  • 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; }