在javascript中同时映射和缩小数组

时间:2017-09-22 15:18:13

标签: javascript arrays mapreduce reduce

我有一个~1800对象的数组表示在联盟中玩的游戏。我需要一个包含每个团队对象的新数组,并且将包含4个新字段(winslossestiespoints)。以下是我正在使用的数组的示例:

[
  {
    "homeGoals": 2,
    "gameId": "12221",
    "homeTeam": {
      "id": "aasfdsf1",
      "teamName": "Team 1"
    },
    "awayTeam": {
      "id": "aasfdsf2",
      "teamName": "Team 2"
    },
    "id": "ggaew1",
    "awayGoals": 4
  },
  {
    "homeGoals": 5,
    "gameId": "12222",
    "homeTeam": {
      "id": "aasfdsf1",
      "teamName": "Team 1"
    },
    "awayTeam": {
      "id": "aasfdsf3",
      "teamName": "Team 3"
    },
    "id": "ggaew2",
    "awayGoals": 1
  },
  {
    "homeGoals": 4,
    "gameId": "12223",
    "homeTeam": {
      "id": "aasfdsf2",
      "teamName": "Team 2"
    },
    "awayTeam": {
      "id": "aasfdsf3",
      "teamName": "Team 3"
    },
    "id": "ggaew3",
    "awayGoals": 4
  },
  {
    "homeGoals": null,
    "gameId": "12223",
    "homeTeam": {
      "id": "aasfdsf2",
      "teamName": "Team 2"
    },
    "awayTeam": {
      "id": "aasfdsf3",
      "teamName": "Team 3"
    },
    "id": "ggaew4",
    "awayGoals": null
  }
]

以下是我需要结果的示例:

 [
  {
    "id": "aasfdsf1",
    "name": "Team 1",
    "wins": 1,
    "losses": 1,
    "ties": 0,
    "points": 2 
  },
  {
    "id": "aasfdsf2",
    "name": "Team 2",
    "wins": 1,
    "losses": 0,
    "ties": 1,
    "points": 3 
  },
  {
    "id": "aasfdsf3",
    "name": "Team 3",
    "wins": 0,
    "losses": 1,
    "ties": 1,
    "points": 1 
  }
]

有些游戏尚未播放,因此homeGoalsawayGoals字段将为空。

到目前为止,我有一个独特的团队列表,仅在游戏完成的地方:

const completedGames = games.filter(x => x.homeGoals !== null)
const homeTeams = [...new Set(completedGames.map(x => x['homeTeam']))];
const awayTeams = [...new Set(completedGames.map(x => x['awayTeam']))];
const teams = [...new Set([...homeTeams, ...awayTeams])]

我知道我需要做一些减少功能,但我很难搞清楚它。我很确定如果我有一个合适的map reduce功能,我之前做的步骤将无关紧要。任何帮助将不胜感激!

3 个答案:

答案 0 :(得分:2)

这可以用flatMap以更简单的方式表达。它不是内置在JS中,但易于实现:

let flatMap = (a, fn) => [].concat(...a.map(fn));

现在,在地图步骤中,您可以发出两个"结果"每场比赛的对象(如果比赛不完整则根本没有结果):

results = flatMap(data, g => {

    if (g.homeGoals === null || g.awayGoals === null)
        return [];

    if (g.homeGoals > g.awayGoals)
        return [
            {id: g.homeTeam.id, r: 'win'},
            {id: g.awayTeam.id, r: 'loss'},
        ];

    if (g.homeGoals < g.awayGoals)
        return [
            {id: g.homeTeam.id, r: 'loss'},
            {id: g.awayTeam.id, r: 'win'},
        ];

    if (g.homeGoals === g.awayGoals)
        return [
            {id: g.homeTeam.id, r: 'tie'},
            {id: g.awayTeam.id, r: 'tie'},
        ];
});

这会创建一个类似

的数组
{ id: 'aasfdsf1', r: 'loss' },
{ id: 'aasfdsf2', r: 'win' },
{ id: 'aasfdsf1', r: 'win' }, etc

很容易减少:

summary = results.reduce((m, {id, r}) => {
    let e = m[id] || {};
    e[r] = (e[r] || 0) + 1;
    return Object.assign(m, {[id]: e})
}, {});

你也可以通过分别将胜利,损失和联系编码为1,-1,0来减少冗长,在这种情况下,映射器变为:

results = flatMap(
    data.filter(g => g.homeGoals !== null),
    g => {
        let d = g.homeGoals - g.awayGoals;
        return [
            {id: g.homeTeam.id, r: Math.sign(+d)},
            {id: g.awayTeam.id, r: Math.sign(-d)},
        ]
    });

答案 1 :(得分:1)

我认为你正在寻找这样的事情:

const hashMapTeams = games.filter(x => x.homeGoals !== null)
.reduce((res, match)=>{
   /* do the calculations here */
   /* put the values on the res object, using res as a HashMap*/
    res["/*the home team id*/"].id = /*id value*/
    res["/*the home team id*/"].name = /*name value*/
    res["/*the home team id*/"].wins= /* the right value */;
    res["/*the home team id*/"].losses= /* the right value */;
    res["/*the home team id*/"].ties= /* the right value */;
    res["/*the home team id*/"].points= /* the right value */;

    res["/*the away team id*/"].id = /*id value*/
    res["/*the away team id*/"].name = /*name value*/
    res["/*the away team id*/"].wins= /* the right value */;
    res["/*the away team id*/"].losses= /* the right value */;
    res["/*the away team id*/"].ties= /* the right value */;
    res["/*the away team id*/"].points= /* the right value */;
 },{});

/* This will convert again the object to an array */
const arrayTeams = Object.keys(hashMapTeams).map(function (key) { return hashMapTeams[key]; });

答案 2 :(得分:0)

这会得到您正在寻找的确切结果:

{
  "id": "aasfdsf1",
  "name": "Team 1",
  "wins": 1,
  "losses": 1,
  "ties": 0,
  "points": 2 
},

我用tenary和括号向你展示了不止一种方法,你可以使用其中任何一种。

let result = [];

your1800ArrayObj.map(data => {      
    let wins = data.wins ? data.wins : 0;
    let losses = data.losses ? data.losses : 0;
    let ties = data['ties'] || 0;
    let points = data['points'] || 0;

    if (data.homeGoals === null && data.awayGoals === null) {
        console.log('game not played')
        } else {
            if (data.homeGoals > data.awayGoals) {
                wins += 1
                points += 1
            } else if (data.homeGoals < data.awayGoals) {
                losses += 1
            } else {
                ties += 1
            }
        }

    result.push({
        id: data.id,
        name: data.homeTeam.teamName ,
        wins: wins,
        losses: losses,
        ties: ties,
        points: points
    })
})

return result
}