简体   繁体   中英

Combine objects with the same values/id and add sum to new object

I have an array of objects that looks like this:

const teams = [{
  name: 'Liverpool',
  won: true,
  opponent: 'Man Utd'
}, {
  name: 'Liverpool',
  won: true,
  opponent: 'Norwich'
}, {
  name: 'Chelsea',
  won: false,
  opponent: 'Arsenal'
},{
  name: 'Newcastle',
  won: true,
  opponent: 'Liverpool'
}];

I want the final array to look like the following. It should only add one team to the new array and calculate how many games the team has won. The order doesn't really matter.

const transformedTeams = [{
    name: 'Liverpool',
    won: 2
  },
  {
    name: 'Newcastle',
    won: 1
  },
  {
    name: 'Chelsea',
    won: 0
  }
];

The code I have written looks like this, but unfortunately isn't returning the correct value:

teams.map(team => {
  if(teams.includes(team.name)) {
    return {
      name: team.name,
      won: team.won === true ? 1 : 0
    }
  }
})

Approach

You could store an object with key-value of team name and number of won match

const teamWonMapping = teams.reduce((acc, team) => {
  acc[team.name] = (acc[team.name] || 0) + (team.won ? 1 : 0)
  return acc
}, {})

const res = Object.entries(teamWonMapping).map(([name, won]) => ({ name, won }))

Full code

 const teams = [ { name: "Liverpool", won: true, opponent: "Man Utd", }, { name: "Liverpool", won: true, opponent: "Liverpool", }, { name: "Chelsea", won: false, opponent: "Arsenal", }, { name: "Newcastle", won: true, opponent: "Liverpool", }, ] const teamWonMapping = teams.reduce((acc, team) => { acc[team.name] = (acc[team.name] || 0) + (team.won ? 1 : 0) return acc }, {}) const res = Object.entries(teamWonMapping).map(([name, won]) => ({ name, won })) console.log(res)


Reference

Array.prototype.reduce()

Object.entries()

I would loop through the array, forming an object in the form:

{
  [team]: [number of wins]
}

and then I would transform the object in the final array. So

const mapping = {}
teams.forEach(team => {
  if (mapping[team.name] === undefined) {
    mapping[team.name] = 0
  }
  mapping[team.name] += team.won ? 1 : 0
})

const result = Object.entries(mapping).map(([name, won]) => {
  return { name, won }
})

You are setting the "won" value to 1 every time you run the code in the return block, instead of incrementing it. Your if statement should see if the "won" value is more than 0. If it is increment using "++" if it's not, set it to 1.

You could create a temporary counter object, keyed by the teams, do the counting and then convert that to your desired structure.

Here is how that could work:

 const teams = [{ name: 'Liverpool', won: true,opponent: 'Man Utd'}, {name: 'Liverpool',won: true,opponent: 'Norwich'}, {name: 'Chelsea',won: false,opponent: 'Arsenal'},{name: 'Newcastle',won: true,opponent: 'Liverpool'}]; let counter = Object.fromEntries(teams.map(({name}) => [name, 0])); for (let {name, won} of teams) counter[name] += won; let result = Object.entries(counter).map(([name, won]) => ({ name, won })); console.log(result);

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