简体   繁体   中英

Javascript ES5: How to Group By a key and create Sub objects from a flat array of key-value objects without using Lodash or Underscore

I have an array of Objects with 4 keys:

[
  {
    "team": "USA",
    "team_profile_id": "10",
    "player": "Captain America",
    "player_id": "10X1"
  },
  {
    "team": "USA",
    "team_profile_id": "10",
    "player": "The hulk",
    "player_id": "10X2"
  },
  {
    "team": "India",
    "team_profile_id": "20",
    "player": "Captain America",
    "player_id": "10X1"
  },
  {
    "team": "India",
    "team_profile_id": "20",
    "player": "SpiderMan",
    "player_id": "10X5"
  }
]

And I want to group my array by "Teams" such that it creates an array of Player objects for each team

 [
  {
    "team": "USA",
    "team_profile_id": "10",
    "Players": [
      {
        "player": "Captain America",
        "player_id": "10X1"
      },
      {
        "player": "The hulk",
        "player_id": "10X2"
      }
    ]
  },
  {
    "team": "India",
    "team_profile_id": "20",
    "Players": [
      {
        "player": "Captain America",
        "player_id": "10X1"
      },
      {
        "player": "SpiderMan",
        "player_id": "10x5"
      }
    ]
  }
]

I am currently trying to use reduce function from MDN prototype but it is not able to handle the sub object creation part.

Currently I have tried:

var group_to_values = result.reduce(function(obj, item) {
            obj[item.team] = obj[item.team] || [];
            obj[item.team].push({
                "team_profile_id":item.team_profile_id,
                "player":item.player,
                "player_id":item.player_id
            });
            return obj;
        }, {});

But it is not giving the desired result

Since the result needs to be an array you can use it as the initial value for reduce instead of an object:

 var players = [ { "team": "USA", "team_profile_id": "10", "player": "Captain America", "player_id": "10X1" }, { "team": "USA", "team_profile_id": "10", "player": "The hulk", "player_id": "10X2" }, { "team": "India", "team_profile_id": "20", "player": "Captain America", "player_id": "10X1" }, { "team": "India", "team_profile_id": "20", "player": "SpiderMan", "player_id": "10X5" } ] var teams = players.reduce(function (teams, player) { var matchingTeams = teams.filter(function(team) { return team.team === player.team; }); var team; if (matchingTeams.length) { team = matchingTeams[0] } else { team = {} teams.push(team) } team.team = player.team; team.team_profile_id = player.team_profile_id; var teamPlayer = { player: player.player, player_id: player.player_id }; team.players = team.players ? team.players.concat(teamPlayer) : [teamPlayer]; return teams }, []) console.log(teams)

While you iterate the players with Array.reduce() , destructure the player object, and separate between the player's properties, and team using spread.

If the team doesn't exist in the accumulator ( r ), create a new object with the team's properties, and the Player: [] property. Push the players into the Players array of the relevant team. Use Object.values() to convert back to an array.

 const data = [{"team":"USA","team_profile_id":"10","player":"Captain America","player_id":"10X1"},{"team":"USA","team_profile_id":"10","player":"The hulk","player_id":"10X2"},{"team":"India","team_profile_id":"20","player":"Captain America","player_id":"10X1"},{"team":"India","team_profile_id":"20","player":"SpiderMan","player_id":"10X5"}] const result = Object.values(data.reduce((r, { team, team_profile_id, ...player }) => { if(!r[team]) r[team] = { team, team_profile_id, Players: [] } r[team].Players.push(player) return r }, {})) console.log(result)

How to ES5 this solution:

  • The main problem is Object.values() , but we can generate a values() functions using Object.keys() .
  • Replace const s with var s, arrow functions with functions, destructuring with manual manual assignments.

 var data = [{"team":"USA","team_profile_id":"10","player":"Captain America","player_id":"10X1"},{"team":"USA","team_profile_id":"10","player":"The hulk","player_id":"10X2"},{"team":"India","team_profile_id":"20","player":"Captain America","player_id":"10X1"},{"team":"India","team_profile_id":"20","player":"SpiderMan","player_id":"10X5"}]; var result = values(data.reduce(function(r, o) { var team = o.team; if(!r[team]) r[team] = { team: team, team_profile_id: o.team_profile_id, Players: [] }; r[team].Players.push({ player: o.player, player_id: o.player_id }) return r }, {})) function values(obj) { return Object.keys(obj).map(function(key) { return obj[key]; }); } console.log(result)

You could find the object and add the new player.

 var data = [{ team: "USA", team_profile_id: "10", player: "Captain America", player_id: "10X1" }, { team: "USA", team_profile_id: "10", player: "The hulk", player_id: "10X2" }, { team: "India", team_profile_id: "20", player: "Captain America", player_id: "10X1" }, { team: "India", team_profile_id: "20", player: "SpiderMan", player_id: "10X5" }], result = data.reduce((r, { team, team_profile_id, player, player_id }) => { var temp = r.find(q => q.team_profile_id === team_profile_id); if (!temp) r.push(temp = { team, team_profile_id, Players: [] }); temp.Players.push({ player, player_id }); return r; }, []); console.log(result);
 .as-console-wrapper { max-height: 100% !important; top: 0; }

This is probably not the best way to do it but it works.

 const players = [ { "team": "USA", "team_profile_id": "10", "player": "Captain America", "player_id": "10X1" }, { "team": "USA", "team_profile_id": "10", "player": "The hulk", "player_id": "10X2" }, { "team": "India", "team_profile_id": "20", "player": "Captain America", "player_id": "10X1" }, { "team": "India", "team_profile_id": "20", "player": "SpiderMan", "player_id": "10X5" } ] const teams = players.reduce((arr, player) => { let [team] = arr.filter(t => t.team === player.team) if (!team) { team = { team: player.team, team_profile_id: player.team_profile_id, Players: [] } arr.push(team) } team.Players.push({ player: player.player, player_id: player.player_id }) return arr }, []) console.log(teams)

Try the following. First I create a set of unique team names and then filter the data based on that to get a list of relevant players:

 const data = [ { "team": "USA", "team_profile_id": "10", "player": "Captain America", "player_id": "10X1" }, { "team": "USA", "team_profile_id": "10", "player": "The hulk", "player_id": "10X2" }, { "team": "India", "team_profile_id": "20", "player": "Captain America", "player_id": "10X1" }, { "team": "India", "team_profile_id": "20", "player": "SpiderMan", "player_id": "10X5" } ]; const res = [...new Set(data.map(e => e.team))] .map(teamName => ({ team: teamName, team_profile_id: data.find(e => e.team === teamName).team_profile_id, Players: data .filter(p => p.team === teamName) .map(p => ({ player: p.player, player_id: p.player_id })) })); console.log(res);

Try this:

'use strict';

const inputData = [
  {
    "team": "USA",
    "team_profile_id": "10",
    "player": "Captain America",
    "player_id": "10X1"
  },
  {
    "team": "USA",
    "team_profile_id": "10",
    "player": "The hulk",
    "player_id": "10X2"
  },
  {
    "team": "India",
    "team_profile_id": "20",
    "player": "Captain America",
    "player_id": "10X1"
  },
  {
    "team": "India",
    "team_profile_id": "20",
    "player": "SpiderMan",
    "player_id": "10X5"
  }
];

function groupByTeams(data) {
  // Find the teams
  const teams = data.map(({ team }) => team);
  const uniqueTeams = [...new Set(teams)];

  // Map the array of unique values to return
  // desired result.
  return uniqueTeams.map(team => {
    return {
      team,
      team_profile_id: data.find((thisTeam) => thisTeam.team === team).team_profile_id,
      Players: data
        .filter(thisTeam => thisTeam.team === team)
        .map(({ player, player_id }) => ({ player_id, player }))
    }
  });
}

groupByTeams(inputData);

Try this...

const playerData = [ ... ]
const teamGroups = playerData.reduce ((teamData, playerObj) => {
    const targetTeam = teamData.filter(t => t.team === playerObj.team)[0];

    if (!targetTeam) {
        return [ ...teamData, { 
            team: playerObj.team, 
            team_profile_id: playerObj.team_profile_id, 
            Players: [{ 
                player: playerObj.player, 
                player_id: playerObj.player_id 
            }] 
        }];
    }

    targetTeam.Players.push ({ player: playerObj.player, player_id: playerObj.player_id });
    return teamData;
}, []);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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