Home > Enterprise >  Grouping an array of objects using a key in Javascript
Grouping an array of objects using a key in Javascript

Time:08-20

Does anyone know a way in Vanilla Javascript to group an array of objects based on an object key, then create a new array of objects based on the grouping? Also grouping elements within the element. I hope to make this clear with an example. I have an array of fruits

fruits: [
    {
      id: "645",
      lang: "it",
      name: "Banana",
    },
    {
      id: "3671",
      lang: "it",
      name: "Pesca",
    },
    {
      id: "3671",
      lang: "en",
      name: "Peach",
    },
    {
      id: "124",
      lang: "it",
      name: "Anguria",
    },
    {
      id: "124",
      lang: "en",
      name: "Watermelon",
    },
  ]

I wish the output was this

fruitsGroupedById: [
    {
      id: "645",
      language: [
        {
          lang: "it",
          name: "Banana",
        },
      ],
    },
    {
      id: "3671",
      language: [
        {
          lang: "it",
          name: "Pesca",
        },
        {
          lang: "en",
          name: "Peach",
        },
      ],
    },
    {
      id: "124",
      language: [
        {
          lang: "it",
          name: "Anguria",
        },
        {
          lang: "en",
          name: "Watermelon",
        },
      ],
    },
  ]

CodePudding user response:

For simplicity's sake, I would do it in two steps

  • create an object with the id as the key, and populate it with the data
  • then convert the object to an array

example:

const fruits = [
  { id: "645", lang: "it", name: "Banana" },
  { id: "3671", lang: "it", name: "Pesca" },
  { id: "3671", lang: "en", name: "Peach" },
  { id: "124", lang: "it", name: "Anguria" },
  { id: "124", lang: "en", name: "Watermelon" },
];

const o = {};

fruits.forEach((f) => {
  if (!o[f.id]) {
    // create object if id is not recognized
    o[f.id] = { id: f.id, language: [] };
  }
  // add language
  o[f.id].language.push({ lang: f.lang, name: f.name });
});

// get array without the key
const arr = Object.values(o);

console.log(arr);

CodePudding user response:

you can do it like this (I additionally sorted the array by id, but you can remove the line with the sort method to disable that):

let fruits = [
  { id: "645", lang: "it", name: "Banana" },
  { id: "3671", lang: "it", name: "Pesca" },
  { id: "3671", lang: "en", name: "Peach" },
  { id: "124", lang: "it", name: "Anguria" },
  { id: "124", lang: "en", name: "Watermelon" },
];

let fruitsGroupedById = [];

let ids = fruits
  .map((f) => f.id)
  .filter((item, pos, self) => {
    return self.indexOf(item) == pos;
  })
  .sort((a, b) => parseInt(a) - parseInt(b));

for (let id of ids) {
  fruitsGroupedById.push({
    id,
    language: fruits
      .filter((f) => f.id === id)
      .map((f) => {
        return { lang: f.lang, name: f.name };
      }),
  });
}

console.log(fruitsGroupedById);

CodePudding user response:

I gues you have to iterate over the array in order the do that since this is an array objects and you can't simply achive what you need by using default funtionalities, so;

let newArray = []    
for(let each of fruits){
  //here there will be logic
}

Then on each iteration you gotta create a new object depending on your new structure, so inside the for loop;

let newObjectForEach = {}
newObjectForEach.id = each.id
newObjectForEach.language = []
newObjectForEach.language.push({lang: each.lang, name: each.name})

newArray.push(newObjectForEach)

But this still is not what you are looking for because this is still creating dublicate object with same id, then we gonna need another method to see if the id already populated to the new Array;

function getIndexIfIdExists(id, newArray) {
    return newArray.forEach(element => {
        if (element.id === id) {
            return newArray.indexOf(element)
        }
    })
}

then finally we can wrap up the whole code as

let newArray = []
for (let each of fruits) {
    let newObjectForEach = {}
    let indexOfId = getIndexIfIdExists(each.id, newArray)
    if(indexOfId){
        newArray[indexOfId].language.push({ lang: each.lang, name: each.name })
    } else {
        newObjectForEach.id = each.id
        newObjectForEach.language = []
        newObjectForEach.language.push({ lang: each.lang, name: each.name })
    
        newArray.push(newObjectForEach)
    }
}

function getIndexIfIdExists(id, newArray) {
    return newArray.forEach(element => {
        if (element.id === id) {
            return newArray.indexOf(element)
        }
    })
}

there might be some small syntax error since I didn't test it but I gues you got the logic.

  • Related