【问题标题】:Tidy up a javascript array of objects [duplicate]整理一个javascript对象数组[重复]
【发布时间】:2018-12-28 02:03:20
【问题描述】:

我正在处理的特定数据操作的措辞很困难,所以请原谅这个糟糕的标题 - 我会举一个很好的例子。我有以下 javascript 对象数组,其中包含一些运动数据:

[
    { team: "Knicks", assists: 24 }, 
    { team: "Knicks", assists: 12 }, 
    { team: "Knicks", assists: 17 }, 
    { team: "Knicks", assists: 19 }, 
    { team: "Warriors", assists: 31 }, 
    { team: "Warriors", assists: 25 }, 
    { team: "Warriors", assists: 20 }, 
    { team: "Spurs", assists: 15 }, 
    { team: "Spurs", assists: 17 }, 
    { team: "Spurs", assists: 32 }, 
    { team: "Spurs", assists: 12 }, 
    { team: "Spurs", assists: 18 }
]

并且想整理一下,使数据看起来像这样:

[
    { team: "Knicks", assists: [24, 36, 53, 72] },
    { team: "Warriors", assists: [31, 56, 76] },
    { team: "Spurs", assists: [15, 32, 64, 76, 94] }

]

原始对象数组中的每个唯一团队都会在新数组中接收自己的对象,而助攻值现在是助攻值的累积总和。我相当肯定,原始对象数组总是以正确的方式排序,这样从上到下循环将产生正确的累积和。

非常感谢任何帮助,谢谢!

【问题讨论】:

  • 对此有任何尝试吗?可以分享一下吗?
  • “整理”不是指“写我的代码”吗?显示您尝试过的内容

标签: javascript data-manipulation


【解决方案1】:

您可以使用reduce 方法构建一个对象,然后使用Object.values 方法获取对象数组。

const data = [{"team":"Knicks","assists":24},{"team":"Knicks","assists":12},{"team":"Knicks","assists":17},{"team":"Knicks","assists":19},{"team":"Warriors","assists":31},{"team":"Warriors","assists":25},{"team":"Warriors","assists":20},{"team":"Spurs","assists":15},{"team":"Spurs","assists":17},{"team":"Spurs","assists":32},{"team":"Spurs","assists":12},{"team":"Spurs","assists":18}]

const result = data.reduce((r, {team, assists}) => {
  if(!r[team]) r[team] = {team, assists: [assists]}
  else r[team].assists.push(r[team].assists.slice(-1)[0] + assists);
  return r;
}, {})

console.log(Object.values(result))

【讨论】:

  • 感谢对此的快速响应——我认为 reduce 是正确的方法并尝试过,但没有成功。我应该希望能够在最后调整它以返回数组中的累积和
  • 如原Q所示
  • 将 else() 大小写更改为:r[team].assists.push(r[team].assists[r[team].assists.length - 1] + assists); 可以解决问题,尽管有点混乱
  • 没注意到,更新了我的答案。
【解决方案2】:

你也可以像这样使用 array#forEach() 方法:

const teams= [
    { team: "Knicks", assists: 24 }, 
    { team: "Knicks", assists: 12 }, 
    { team: "Knicks", assists: 17 }, 
    { team: "Knicks", assists: 19 }, 
    { team: "Warriors", assists: 31 }, 
    { team: "Warriors", assists: 25 }, 
    { team: "Warriors", assists: 20 }, 
    { team: "Spurs", assists: 15 }, 
    { team: "Spurs", assists: 17 }, 
    { team: "Spurs", assists: 32 }, 
    { team: "Spurs", assists: 12 }, 
    { team: "Spurs", assists: 18 }
]

let teamGroup = {}

teams.forEach(team => {
  teamGroup[team.team] ? // check if that array exists or not in teamgroup object
    teamGroup[team.team].push(team.assists)  // just push
   : (teamGroup[team.team] = [], teamGroup[team.team].push(team.assists)) // create a new array and push
})

console.log(teamGroup);

【讨论】:

  • 这没有给出正确的结果。它给出{Knicks: [{assists: 31}, {assists: 25}, {assists: 20}]},而不是[{team: "Knicks", assists: [31, 25, 20]}]
  • 你可以像“teamGroup[team.team].push(team.assists))”一样推送。我已经更新了上面的答案。我希望现在它可以解决您的问题。
【解决方案3】:

这是函数式编程方法,使用临时 ES6 Map

const teams = [{ team: "Knicks", assists: 24 },{ team: "Knicks", assists: 12 },{ team: "Knicks", assists: 17 },{ team: "Knicks", assists: 19 },{ team: "Warriors", assists: 31 },{ team: "Warriors", assists: 25 },{ team: "Warriors", assists: 20 },{ team: "Spurs", assists: 15 },{ team: "Spurs", assists: 17 },{ team: "Spurs", assists: 32 },{ team: "Spurs", assists: 12 },{ team: "Spurs", assists: 18 }];

const result = Array.from(
    teams.reduce( (acc, {team, assists}) => acc.set(team, (acc.get(team) || []).concat(assists)), new Map),
    ([team, assists]) => ({team, assists})
);

console.log(result);

【讨论】:

    【解决方案4】:

    lodash 库有一个方便的 _.groupBy 可以为您完成相当多的工作。

    如果你这样做const groups = _.groupBy(data, team),你会得到:

    {
        "Knicks": [
            { "team": "Knicks", "assists": 24},
            { "team": "Knicks", "assists": 12},
            { "team": "Knicks", "assists": 17},
            { "team": "Knicks", "assists": 19},
        ],
        // ...
    }
    

    那么,

    const result = _.map(groups, (teamData, teamName) => {
        // Convert teamData array into a single record
        const assists = _.map(teamData, "assists"); // e.g. [24, 12, 17, 19]
        return { team: teamName, assists: runningTotal(assists) };
    });
    
    // Turns an array like [1,2,3,4] into an array like [1,3,6,10]
    function runningTotal(array) {
        let prev = 0;
        return array.map(next => {
            prev = next + prev;
            return prev;
        });
    }
    

    这给出了预期的结果。


    这种方法并不比使用reduce 的解决方案短很多,但我个人发现像groupBymap 这样的高阶运算比reduce 更容易推理。 (当然,这需要 lodash 或类似实现的 groupBy 函数)


    编辑:我完全错过了助攻不仅仅是一系列助攻,而是一个运行总数。增加了一点来解释这一点。代码比 reduce 解决方案长得多,但 IMO 更清晰。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-11-14
      • 1970-01-01
      • 2013-04-20
      • 2019-06-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-05-23
      相关资源
      最近更新 更多