简体   繁体   English

Javascript:合并具有不同键/值对的数组中的对象,并从相同的键中获取总和

[英]Javascript: Merge Objects in array with different key/value pairs, and getitng the sum from the same keys

So what I have is an array of objects所以我有一个对象数组

[
    {
        "email": "jacob@whatever.com",
        "actionsCount": {
            "edit record": 5,
            "assign to specialist": 1
        },
        "changesTotal": 6
    },
    {
        "email": "trav1@whatever.com",
        "actionsCount": {
            "edit record": 13,
            "duplicate": 5,
            "return for changes": 1
        },
        "changesTotal": 19
    },
    {
        "email": "donbossman@whatever.com",
        "actionsCount": {
            "edit record": 5
        },
        "changesTotal": 5
    },
    {
        "email": "donbossman@whatever.com",
        "actionsCount": {
            "edit record": 11,
            "return for changes": 1,
            "assign to specialist": 1
        },
        "changesTotal": 13
    },
    {
        "email": "Marilla@whatever.com",
        "actionsCount": {
            "edit record": 7
        },
        "changesTotal": 7
    },
    {
        "email": "Marilla@whatever.com",
        "actionsCount": {
            "edit record": 6
        },
        "changesTotal": 6
    },
    {
        "email": "natalie1@whatever.com",
        "actionsCount": {
            "edit record": 5,
            "assign to specialist": 1
        },
        "changesTotal": 6
    },
    {
        "email": "natalie1@whatever.com",
        "actionsCount": {
            "assign to specialist": 2,
            "edit record": 17
        },
        "changesTotal": 19
    },
    {
        "email": "psteacher@whatever.com",
        "actionsCount": {
            "edit record": 2,
            "assign to specialist": 2
        },
        "changesTotal": 4
    },
    {
        "email": "psteacher@whatever.com",
        "actionsCount": {
            "edit record": 17,
            "duplicate": 2
        },
        "changesTotal": 19
    }
]

As you can see there will be multiple entries under the same email, these correspond to each month that user did some actions, as such new entries will populate each month, some most of them by the same users.如您所见,在同一个 email 下会有多个条目,这些条目对应于用户每个月执行的某些操作,因此每个月都会填充新条目,其中大部分都是由相同的用户创建的。 I don't know all of the actions, but I can be assured that the actions will all be spelled the same.我不知道所有的动作,但我可以保证这些动作的拼写都是一样的。 The data is old so as you can see someone used spaces for the key which is another task for another day.数据很旧,因此您可以看到有人使用空格作为密钥,这是另一天的另一项任务。

I want to combine objects by the same email, then sum the same actions across the months, and add actions that are present in one month but not another.我想按相同的 email 组合对象,然后对几个月内的相同操作求和,并添加一个月内存在但另一个月内不存在的操作。

So as an example donbossman@whatever.com end result would look like因此,例如donbossman@whatever.com最终结果看起来像

Would look like看起来像

[{
  "email": "donbossman@whatever.com",
  "actionsCount": {
      "edit record": 16,
      "return for changes": 1,
      "assign to specialist": 1
  }
  "changesTotal": 18
}]

So because edit record is present in both occurrences of actionsCount they are simply added up, and return for changes and assign to specialist are present in one but not the other因此,因为edit record在两次出现的actionsCount中都存在,所以它们被简单地加起来,并且return for changesassign to specialist出现在一个而不是另一个中

Right now I feel like I'm close to what I'm trying to achieve?现在我觉得我离我想要达到的目标很近了? My current approach is as follows我目前的做法如下

tier2CollectorsActions.reduce((acc, {email, actionsCount}) => {
          acc[email] ??= {email: email, actionsCount: []};
          if(Array.isArray(actionsCount))
            acc[email].actionsCount = _.merge(acc[email].actionsCount, actionsCount)
          else
            acc[email].actionsCount.push(actionsCount);
          return acc;
        }, {})

Which gives me back这让我回来

{
    "email": "natalie1@whatever.com",
    "actionsCount": [
        {
            "edit record": 5,
            "assign to specialist": 1
        },
        {
            "assign to specialist": 2,
            "edit record": 17
        }
    ]
}

As you can see each actionsCount array corresponds to the two separate natalie1@whatever.com object's actionsCount data.如您所见,每个actionsCount数组对应于两个单独的natalie1@whatever.com对象的actionsCount数据。 I need the actionsCount data back not as an array but an object, I'm doing it as an array in the example bc its so far been the only way I can get the data from both actionCounts .我需要的 actionsCount 数据不是作为数组而是作为 object 返回,我在示例中将其作为数组 bc 到目前为止,这是我可以从两个actionCounts获取数据的唯一方法。 I've been trying to use Object.value and reduce but I haven't quite gotten yet but I feel like I'm so close.我一直在尝试使用 Object.value 并减少,但我还没有完全理解,但我觉得我已经很接近了。

Any direction/tips/suggestions would be much appreciated任何方向/提示/建议将不胜感激

You were close.你很接近。

  1. Seems like actionsCount is always an object, never an array似乎actionsCount始终是 object,而不是数组
  2. Just add the things to the object只需将东西添加到 object

 const data = [{ "email": "jacob@whatever.com", "actionsCount": { "edit record": 5, "assign to specialist": 1 }, "changesTotal": 6 }, { "email": "trav1@whatever.com", "actionsCount": { "edit record": 13, "duplicate": 5, "return for changes": 1 }, "changesTotal": 19 }, { "email": "donbossman@whatever.com", "actionsCount": { "edit record": 5 }, "changesTotal": 5 }, { "email": "donbossman@whatever.com", "actionsCount": { "edit record": 11, "return for changes": 1, "assign to specialist": 1 }, "changesTotal": 13 }, { "email": "Marilla@whatever.com", "actionsCount": { "edit record": 7 }, "changesTotal": 7 }, { "email": "Marilla@whatever.com", "actionsCount": { "edit record": 6 }, "changesTotal": 6 }, { "email": "natalie1@whatever.com", "actionsCount": { "edit record": 5, "assign to specialist": 1 }, "changesTotal": 6 }, { "email": "natalie1@whatever.com", "actionsCount": { "assign to specialist": 2, "edit record": 17 }, "changesTotal": 19 }, { "email": "psteacher@whatever.com", "actionsCount": { "edit record": 2, "assign to specialist": 2 }, "changesTotal": 4 }, { "email": "psteacher@whatever.com", "actionsCount": { "edit record": 17, "duplicate": 2 }, "changesTotal": 19 } ] const result = data.reduce((acc, { email, actionsCount, changesTotal }) => { acc[email]??= { email: email, actionsCount: {}, changesTotal: 0 }; Object.entries(actionsCount).forEach(([key, value]) => { acc[email].actionsCount[key]??= 0 acc[email].actionsCount[key] += value }) acc[email].changesTotal += changesTotal return acc; }, {}) console.log(result)

Use lodash's _.groupBy() to group the items by email, and then map the groups and merge them using _.mergeWith() .使用 lodash 的_.groupBy()将项目按 email 分组,然后按 map 分组并使用_.mergeWith()合并它们。 In the customizer function of _.mergeWith() check if either of the values is a number (since one of them might be undefined ), and if they are numbers sum them._.mergeWith()的定制器 function 中,检查两个值中的任何一个是否为数字(因为其中一个可能是undefined ),如果它们是数字,则对它们求和。 If not, let _.mergeWith() handle them by return undefined :如果没有,让_.mergeWith()通过返回undefined来处理它们:

 const { flow, groupBy, map, mergeWith, isNumber } = _ const fn = flow( arr => groupBy(arr, 'email'), groups => map(groups, items => mergeWith(...items, (o1, o2) => isNumber(o1) || isNumber(o2)? (o1?? 0) + (o2?? 0): undefined )) ) const arr = [{"email":"jacob@whatever.com","actionsCount":{"edit record":5,"assign to specialist":1},"changesTotal":6},{"email":"trav1@whatever.com","actionsCount":{"edit record":13,"duplicate":5,"return for changes":1},"changesTotal":19},{"email":"donbossman@whatever.com","actionsCount":{"edit record":5},"changesTotal":5},{"email":"donbossman@whatever.com","actionsCount":{"edit record":11,"return for changes":1,"assign to specialist":1},"changesTotal":13},{"email":"Marilla@whatever.com","actionsCount":{"edit record":7},"changesTotal":7},{"email":"Marilla@whatever.com","actionsCount":{"edit record":6},"changesTotal":6},{"email":"natalie1@whatever.com","actionsCount":{"edit record":5,"assign to specialist":1},"changesTotal":6},{"email":"natalie1@whatever.com","actionsCount":{"assign to specialist":2,"edit record":17},"changesTotal":19},{"email":"psteacher@whatever.com","actionsCount":{"edit record":2,"assign to specialist":2},"changesTotal":4},{"email":"psteacher@whatever.com","actionsCount":{"edit record":17,"duplicate":2},"changesTotal":19}] const result = fn(arr) console.log(result)
 <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js" integrity="sha512-WFN04846sdKMIP5LKNphMaWzU7YpMyCU245etK3g/2ARYbPK9Ub18eG+ljU96qKRCWh+quCY7yefSmlkQw1ANQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>

You shouldn't initialize actionsCount to an array.您不应该将actionsCount初始化为数组。 That's causing it to push each actionsCount object onto the array, instead of combining the properties.这导致它将每个actionsCount object 推入数组,而不是组合属性。

You need to loop over the properties in actionsCount , adding them to the corresponding value in acc[email] .您需要遍历actionsCount中的属性,将它们添加到acc[email]中的相应值。

 const tier2CollectorsActions = [{ "email": "jacob@whatever.com", "actionsCount": { "edit record": 5, "assign to specialist": 1 }, "changesTotal": 6 }, { "email": "trav1@whatever.com", "actionsCount": { "edit record": 13, "duplicate": 5, "return for changes": 1 }, "changesTotal": 19 }, { "email": "donbossman@whatever.com", "actionsCount": { "edit record": 5 }, "changesTotal": 5 }, { "email": "donbossman@whatever.com", "actionsCount": { "edit record": 11, "return for changes": 1, "assign to specialist": 1 }, "changesTotal": 13 }, { "email": "Marilla@whatever.com", "actionsCount": { "edit record": 7 }, "changesTotal": 7 }, { "email": "Marilla@whatever.com", "actionsCount": { "edit record": 6 }, "changesTotal": 6 }, { "email": "natalie1@whatever.com", "actionsCount": { "edit record": 5, "assign to specialist": 1 }, "changesTotal": 6 }, { "email": "natalie1@whatever.com", "actionsCount": { "assign to specialist": 2, "edit record": 17 }, "changesTotal": 19 }, { "email": "psteacher@whatever.com", "actionsCount": { "edit record": 2, "assign to specialist": 2 }, "changesTotal": 4 }, { "email": "psteacher@whatever.com", "actionsCount": { "edit record": 17, "duplicate": 2 }, "changesTotal": 19 } ]; const result = tier2CollectorsActions.reduce((acc, { email, actionsCount }) => { acc[email]??= { email: email, actionsCount: {} }; Object.entries(actionsCount).forEach(([key, value]) => { acc[email].actionsCount[key] = (acc[email].actionsCount[key] || 0) + value; }); return acc; }, {}) console.log(result);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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