Home > Blockchain >  JS iterate array items and group them in new array by property
JS iterate array items and group them in new array by property

Time:03-30

I have an array of objects

    listOfItems: any[] = [
      {text: 'Hola', group: 'espanian'},
      {text: 'Hello', group: 'english'},
      {text: 'How are you', group: 'english'},
      {text: 'Tere', group: 'estonian'},
    ]

I would like to iterate over an array and create another array with categorized objects

    groups: any[] = [
    [
      { name: 'english', 
        items: [
           {text: 'Hello', group: 'english'},
           {text: 'How are you', group: 'english'},
        ]
      },
      { name: 'espanian', 
        items: [
           {text: 'Hola', group: 'espanian'}
        ]
      },
      { name: 'estonian', 
        items: [
           {text: 'Tere', group: 'estonian'}
        ]
      },
    ]

What is the most dynamic way to do it? The number of groups could be over 30, so I would like to avoid doing if or equals checks inside the loop

I mean dynamic - is basically without any explicit checks like item.group = 'english'

I have tried to achieve something similar with

      let result: any = [];
      this.listOfItems.forEach(p => {
        var key = p.group;
        result[key] = result[key] || [];
        result[key].push(p);
      })

however the result is not exactly what I am looking for

[
   {'english': [
             {text: 'Hello', group: 'english'},
             {text: 'How are you', group: 'english'},
            ]
   }, 
   {'espanian': [
             {text: 'Hola', group: 'espanian'},
            ]
   },
]

CodePudding user response:

  1. Why any[]?
  2. Maps are really great for these types of data manipulations. Check it out:
interface Item {
    text: string;
    group: string;
}

interface Categorized {
    name: string;
    items: Item[];
}

const itemList: Item[] = [
    { text: 'Hola', group: 'espanian' },
    { text: 'Hello', group: 'english' },
    { text: 'How are you', group: 'english' },
    { text: 'Tere', group: 'estonian' },
];

const categorize = (list: Item[]): Categorized[] => {
    const map: Record<string, Categorized> = {};

    list.forEach((item) => {
        if (!map[item.group]) {
            map[item.group] = { name: item.group, items: [item] };
            return;
        }

        map[item.group].items.push(item);
    });

    return Object.values(map);
};

console.log(categorize(itemList));

We're only using one loop.

Compiled:

var itemList = [
    { text: 'Hola', group: 'espanian' },
    { text: 'Hello', group: 'english' },
    { text: 'How are you', group: 'english' },
    { text: 'Tere', group: 'estonian' },
];
var categorize = function (list) {
    var map = {};
    list.forEach(function (item) {
        if (!map[item.group]) {
            map[item.group] = { name: item.group, items: [item] };
            return;
        }
        map[item.group].items.push(item);
    });
    return Object.values(map);
};
console.log(categorize(itemList));

CodePudding user response:

Array.reduce implementation.

const listOfItems = [
  { text: 'Hola', group: 'espanian' },
  { text: 'Hello', group: 'english' },
  { text: 'How are you', group: 'english' },
  { text: 'Tere', group: 'estonian' },
];

const output = listOfItems.reduce((acc, curr) => {
  const matchItem = acc.find(item => item.name === curr.group);
  if (matchItem) {
    matchItem.items.push(curr);
  } else {
    acc.push({
      name: curr.group,
      items: [curr]
    })
  }
  return acc;
}, []);
console.log(output);

For those who are concerned about double loop, you can achieve the above one with a single loop using.

const listOfItems = [
  { text: 'Hola', group: 'espanian' },
  { text: 'Hello', group: 'english' },
  { text: 'How are you', group: 'english' },
  { text: 'Tere', group: 'estonian' },
];

const output = listOfItems.reduce((acc, curr) => {
  acc[curr.group] ? acc[curr.group].items.push(curr) : acc[curr.group] = {
    name: curr.group,
    items: [curr]
  };
  return acc;
}, {});
console.log(Object.values(output));

CodePudding user response:

Try with the below code

const modifiedList = listOfItems.reduce((acc, item) => {
 if(!acc[item.group]) acc[item.group]=[item];
 else acc[item.group].push(item)
}, {});
let newList = [];
for(let item in modifiedList) {
 newList.push({
   name: item,
   items: modifiedList[item]
 })
}

CodePudding user response:

const listOfItems = [
    {text: 'Hola', group: 'espanian'},
    {text: 'Hello', group: 'english'},
    {text: 'How are you', group: 'english'},
    {text: 'Tere', group: 'estonian'},
]

const groups = listOfItems.reduce((acc, {text, group}) => {
    if(!acc[group]) {
        acc[group] = {name: group, items: []}
    }
    acc[group].items.push({text, group})
    return acc;
}, {});
console.log(Object.values(groups));

  • Related