Javascript: raggruppa array di oggetti in base a valori comuni con etichetta

Sep 08 2020

Sto cercando di trasformare un array di oggetti in un altro array di oggetti raggruppandoli per un valore specifico e aggiungendo quel valore come etichetta ed estraendolo dall'oggetto nel nuovo array.

Input: Quindi, ad esempio, ho questo array di oggetti:

let tech = [
  { id: 1, grouping: "Front End", value: "HTML" },
  { id: 2, grouping: "Front End", value: "React" },
  { id: 3, grouping: "Back End", value: "Node" },
  { id: 4, grouping: "Back End", value: "PHP" },
];

Previsto: sto cercando di capire come posso arrivare a questo, dove c'è un'etichetta per ciascuno dei raggruppamenti univoci e l'array di opzioni contenente i valori di quel raggruppamento.

[
  {
    label: "Front End",
    options: [
      { id: 1, value: "HTML" },
      { id: 2, value: "React" },
    ],
  },
  {
    label: "Back End",
    options: [
      { id: 3, value: "Node" },
      { id: 4, value: "PHP" },
    ],
  },
]

Il più vicino a cui sono stato in grado di arrivare è usare la riduzione al gruppo tramite la chiave di raggruppamento:

const groupedTech = tech.reduce((acc, value) => {
  // Group initialization
  if (!acc[value.grouping]) {
    acc[value.grouping] = [];
  }
 
  // Grouping
  acc[value.grouping].push(value);
 
  return acc;
}, {});

Il che mi dà questo:

{
  "Front End": [
    { id: 1, grouping: "Front End", value: "HTML" },
    { id: 2, grouping: "Front End", value: "React" },
  ],
  "Back End": [
    { id: 3, grouping: "Back End", value: "Node" },
    { id: 4, grouping: "Back End", value: "PHP" },
  ],
}

Ma questo restituisce un oggetto non un array e non rimuove il valore di raggruppamento. Non sono stato in grado di capire come raggruppare correttamente perché nell'array di oggetti non ho trovato un modo efficiente per confrontarmi per vedere se il raggruppamento esiste e in tal caso aggiungerlo a quell'array annidato. Sarei meglio usare qualcosa come .map () ? Apprezza eventuali contatti / apprendimenti!

Risposte

3 HaoWu Sep 08 2020 at 12:18

Sei molto vicino, racchiudi semplicemente le voci dei valori-chiave del risultato che hai ottenuto in una mapfunzione:

let tech = [
  { id: 1, grouping: "Front End", value: "HTML" },
  { id: 2, grouping: "Front End", value: "React" },
  { id: 3, grouping: "Back End", value: "Node" },
  { id: 4, grouping: "Back End", value: "PHP" },
];

const groupedTech = Object.entries(
  // What you have done
  tech.reduce((acc, { id, grouping, value }) => {
    // Group initialization
    if (!acc[grouping]) {
      acc[grouping] = [];
    }
    
    // Grouping
    // FIX: only pushing the object that contains id and value
    acc[grouping].push({ id, value });

    return acc;
  }, {})
).map(([label, options]) => ({ label, options }));

console.log(groupedTech);

2 hgb123 Sep 08 2020 at 12:18

Devi solo fare un'altra manipolazione con Object.entriese.map

let tech = [
  { id: 1, grouping: 'Front End', value: 'HTML' },
  { id: 2, grouping: 'Front End', value: 'React' },
  { id: 3, grouping: 'Back End', value: 'Node' },
  { id: 4, grouping: 'Back End', value: 'PHP' }
]

const groupedTech = tech.reduce((acc, value) => {
  // Group initialization
  if (!acc[value.grouping]) {
    acc[value.grouping] = []
  }

  // Grouping
  acc[value.grouping].push(value)

  return acc
}, {})

const res = Object.entries(groupedTech).map(([label, options]) => ({
  label,
  options
}))

console.log(res)

2 Nick Sep 08 2020 at 12:23

Una piccola variazione sulle altre due risposte se vuoi ottenere esattamente l'output che specifichi:

let tech = [{
    id: 1,
    grouping: "Front End",
    value: "HTML"
  },
  {
    id: 2,
    grouping: "Front End",
    value: "React"
  },
  {
    id: 3,
    grouping: "Back End",
    value: "Node"
  },
  {
    id: 4,
    grouping: "Back End",
    value: "PHP"
  },
];

const groupedTech = Object.entries(
    tech.reduce((acc, value) => {
      // Group initialization
      if (!acc[value.grouping]) {
        acc[value.grouping] = [];
      }

      // Grouping
      acc[value.grouping].push({
        id: acc[value.grouping].length+1,
        value: value.value
      });

      return acc;
    }, {}))
  .map(([label, options]) => ({
    label,
    options
  }));

console.log(groupedTech);

2 Phil Sep 08 2020 at 12:25

Di solito mi piace creare una Mapcoppia chiave / valore e poi trasformare quelle voci nel risultato finale (di solito usando Array.prototype.map()o Array.from()).

const tech = [
  { id: 1, grouping: "Front End", value: "HTML" },
  { id: 2, grouping: "Front End", value: "React" },
  { id: 3, grouping: "Back End", value: "Node" },
  { id: 4, grouping: "Back End", value: "PHP" },
];

const groupedMap = tech.reduce((map, { grouping, ...option }) => {
  if (!map.has(grouping)) {
    map.set(grouping, [])
  }
  map.get(grouping).push(option)
  return map
}, new Map())

const groupedTech = Array.from(groupedMap, ([ label, options ]) => ({
  label,
  options
}))

console.log(groupedTech)

2 charlietfl Sep 08 2020 at 12:37

Utilizzo di una mappa e dei valori di mappa # ()

const grouped = tech.reduce((m,{grouping:label, ...rest})=>{
    const group = m.get(label) || {label, options:[]};
    group.options.push({...rest})
    return m.set(label, group)
},new Map)

console.log([...grouped.values()])
<script>
let tech=[{id:1,grouping:"Front End",value:"HTML"},{id:2,grouping:"Front End",value:"React"},{id:3,grouping:"Back End",value:"Node"},{id:4,grouping:"Back End",value:"PHP"}];
</script>