ES6: Как мне распутать внутренние массивы и выровнять массив JSON?

#javascript #json #ecmascript-6 #lodash #transformation

#javascript #json #ecmascript-6 #Lodash #преобразование

Вопрос:

Представьте, что у меня есть следующий массив JSON:

 [
  {
    "team": "Colts",
    "players": [
      {
        "name": "Andrew Luck",
        "position": "quarterback"
      },
      {
        "name": "Quenton Nelson",
        "position": "guard"
      }
    ]
  },
  {
    "team": "Patriots",
    "players": [
      {
        "name": "Tom Brady",
        "position": "quarterback"
      },
      {
        "name": "Shaq Mason",
        "position": "guard"
      }
    ]
  }
]
  

И я хочу преобразовать и выровнять JSON следующим образом:

 [
  {
    "name": "Andrew Luck",
    "position": "quarterback",
    "team": "Colts"
  },
  {
    "name": "Quenton Nelson",
    "position": "guard",
    "team": "Colts"
  },
  {
    "name": "Tom Brady",
    "position": "quarterback",
    "team": "Patriots"
  },
  {
    "name": "Shaq Mason",
    "position": "guard",
    "team": "Patriots"
  }
]
  

Как бы я сделал это с помощью синтаксиса ES6 или Lodash?

Ответ №1:

С помощью простых циклов (ES2015):

 const players = [];
for (const team of teams) {
  for (const player of team.players) {
    players.push(Object.assign({team: team.team}, player));
  }
}
  

Вы можете использовать object spread вместо Object.assign , если ваша среда поддерживает это.

С Array#flatMap (официально будет частью ES2019 или использовать Lodash):

 const players = teams.flatMap(
  team => team.players.map(player => {...player, team: team.team})
);
  

Ответ №2:

Используйте Array#reduce метод вместе с Array#map методом.

 let res = data.reduce((arr, { team, players }) => arr.concat(players.map( obj => ({...obj, team }))), []);

// or
let res = data.reduce((arr, { team, players }) => [...arr, ...players.map( obj => ({...obj, team }))], []);

// or
let res = data.reduce((arr, { team, players }) => (arr.push(...players.map( obj => ({...obj, team }))),arr), []);
  

 var data = [{
    "team": "Colts",
    "players": [{
        "name": "Andrew Luck",
        "position": "quarterback"
      },
      {
        "name": "Quenton Nelson",
        "position": "guard"
      }
    ]
  },
  {
    "team": "Patriots",
    "players": [{
        "name": "Tom Brady",
        "position": "quarterback"
      },
      {
        "name": "Shaq Mason",
        "position": "guard"
      }
    ]
  }
]

let res = data.reduce((arr, {
  team,
  players
}) => arr.concat(players.map(obj => ({ ...obj,
  team
}))), []);


// or
let res1 = data.reduce((arr, {
  team,
  players
}) => [...arr, ...players.map(obj => ({ ...obj,
  team
}))], []);

// or
let res2 = data.reduce((arr, {
  team,
  players
}) => (arr.push(...players.map(obj => ({ ...obj,
  team
}))), arr), []);


console.log(res, res1, res2)  

Ответ №3:

Вы можете использовать lodah _.flatMap() для итерации массива и выравнивания результата. Внутреннее использование _.map() для перебора игроков и добавления team с использованием объекта spread:

 const arr = [{"team":"Colts","players":[{"name":"Andrew Luck","position":"quarterback"},{"name":"Quenton Nelson","position":"guard"}]},{"team":"Patriots","players":[{"name":"Tom Brady","position":"quarterback"},{"name":"Shaq Mason","position":"guard"}]}]

const result = _.flatMap(arr, ({ team, players }) => 
  _.map(players, o => ({ team, ...o }))
)

console.log(result)  
 <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>  

Вы можете сделать то же самое с Array.flatMap() и Array.map() :

 const arr = [{"team":"Colts","players":[{"name":"Andrew Luck","position":"quarterback"},{"name":"Quenton Nelson","position":"guard"}]},{"team":"Patriots","players":[{"name":"Tom Brady","position":"quarterback"},{"name":"Shaq Mason","position":"guard"}]}]

const result = arr.flatMap(({ team, players }) => 
  players.map(o => ({ team, ...o }))
)

console.log(result)  
 <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>  

Ответ №4:

 const data = [
  {
    "team": "Colts",
    "players": [
      {
        "name": "Andrew Luck",
        "position": "quarterback"
      },
      {
        "name": "Quenton Nelson",
        "position": "guard"
      }
    ]
  },
  {
    "team": "Patriots",
    "players": [
      {
        "name": "Tom Brady",
        "position": "quarterback"
      },
      {
        "name": "Shaq Mason",
        "position": "guard"
      }
    ]
  }
]

const flatData = data.map(d => {
  const { team } = d
  const assignedPlayers = d.players.map(player => ({ team, ...player }))
  return assignedPlayers
}).flat()

console.log(flatData)  

Ответ №5:

С помощью ES6 (оператор распространения) наряду с reduce и concat :

 const arr = [{
    "team": "Colts",
    "players": [{
        "name": "Andrew Luck",
        "position": "quarterback"
      },
      {
        "name": "Quenton Nelson",
        "position": "guard"
      }
    ]
  },
  {
    "team": "Patriots",
    "players": [{
        "name": "Tom Brady",
        "position": "quarterback"
      },
      {
        "name": "Shaq Mason",
        "position": "guard"
      }
    ]
  }
]

console.log(arr.reduce((acc, obj) => {
  return acc.concat(...obj.players.map(player => {
    return Object.assign({
      team: obj.team
    }, player)
  }))
}, []));  

Комментарии:

1. Для пояснения будущим посетителям: reduce существовал до ES6.

Ответ №6:

Это можно сделать просто с помощью следующего кода! Проверьте это!

 var inputArray = [{"team":"Colts","players":[{"name":"Andrew Luck","position":"quarterback"},{"name":"Quenton Nelson","position":"guard"}]},{"team":"Patriots","players":[{"name":"Tom Brady","position":"quarterback"},{"name":"Shaq Mason","position":"guard"}]}]

var result = [];
inputArray.forEach(function(elem) {
  const players = elem.players;
  players.forEach(function(child) {
    const obj = {};
    obj["name"] = child.name;
    obj["position"] = child.position;
    obj["team"] = elem.team;
    result.push(obj);
  });
});

console.log(result);  
 .as-console-wrapper{max-height: 100% !important; top:0px;}  

Ответ №7:

Вот еще одна альтернатива с комбинацией Array.reduce() и Array.forEach() :

 let input = [
  {
    "team": "Colts",
    "players": [
      {
        "name": "Andrew Luck",
        "position": "quarterback"
      },
      {
        "name": "Quenton Nelson",
        "position": "guard"
      }
    ]
  },
  {
    "team": "Patriots",
    "players": [
      {
        "name": "Tom Brady",
        "position": "quarterback"
      },
      {
        "name": "Shaq Mason",
        "position": "guard"
      }
    ]
  }
];

let output = input.reduce((acc, {team, players}) =>
{
    players.forEach(({name, position}) => acc.push({name, position, team}));
    return acc;
}, []);

console.log(output);  
 .as-console {background-color:black !important; color:lime;}
.as-console-wrapper {max-height:100% !important; top:0;}