Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Javascript - group array of objects by common values with label

I am trying to turn an array of objects into another array of objects by grouping by a specific value and adding that value as label and taking it out of the object in the new array.

Input: So for instance I have this array of objects:

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" },
];

Expected: I am looking to try and figure out how I can get to this, where there is a label for each of the unique groupings and options array containing the values of that grouping.

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

The closest I have been able to get to is using reduce to group by the grouping key:

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

Which gives me this:

{
  "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" },
  ],
}

But this returns object not an array and doesn't remove the grouping value. I have not been able to figure out how to group properly because in the array of objects I have not found an efficient way to compare against to see if the grouping exists and if so add to that nested array. Would I be better off using something like .map()? Appreciate any leads/learnings!

like image 343
mcdev Avatar asked Sep 08 '20 05:09

mcdev


People also ask

What is the difference between [] and {} in JavaScript?

{} is shorthand for creating an empty object. You can consider this as the base for other object types. Object provides the last link in the prototype chain that can be used by all other objects, such as an Array . [] is shorthand for creating an empty array.

How do you group objects in an array?

The most efficient method to group by a key on an array of objects in js is to use the reduce function. The reduce() method executes a reducer function (that you provide) on each element of the array, resulting in a single output value.

How do you group an array of objects using a key?

The most effective way to group objects by key is by using the Reduce function in js. The Reduce() methods execute reducer functions on all the data points on an array and result in an output value of the same value.

How do you group an array in JavaScript?

The group() method executes the callbackFn function once for each index of the array, returning a string (or value that can be coerced to a string) indicating the group of the element. A new property and array is created in the result object for each unique group name that is returned by the callback.


3 Answers

You're very close, just wrap the key-value entries of the result you've got in a map function:

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);
like image 139
Hao Wu Avatar answered Nov 02 '22 08:11

Hao Wu


You just have to do one more manipulation with Object.entries and .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)
like image 29
hgb123 Avatar answered Nov 02 '22 06:11

hgb123


A minor variation on the other two answers if you want to get exactly the output you specify:

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);
like image 23
Nick Avatar answered Nov 02 '22 06:11

Nick