简体   繁体   中英

How to groupBy array of object in JavaScript

I want to groupBy my array of an object into some another desired array of objects. I go through several tutorials but didn't get the appropriate output.

What I want is based on their groupBy properties I want to group all the elements

Here is my input

permissions= [
    {
      code: 'U00',
      permission_name: 'Read User',
      groupBy: 'User',
      icon: 'user',
    },
    {
      code: 'U01',
      permission_name: 'Create User',
      groupBy: 'User',
      icon: 'user',
    },
  
    {
      code: 'B00',
      permission_name: 'Read Batch',
      groupBy: 'Batch',
      icon: 'user',
    },
    {
      code: 'B01',
      permission_name: 'Create Batch',
      groupBy: 'Batch',
      icon: 'user',
    },
    {
      code: 'B10',
      permission_name: 'Update Batch',
      groupBy: 'Batch',
      icon: 'user',
    },
  ];

Required output

 Output = [
    {
      label: 'User',
      icon: 'user',
      children: [
        {
          label: 'Create Users',
        },
        {
          label: 'Read All Users',
        },
      
      ],
    },
    {
      label: 'Batch',
      children: [
        {
          label: 'Create Batchs',
        },
        {
          label: 'Read All Batch',
        },
        {
          label: 'Update Batch',
        },
        {
          label: 'Disabled Batch',
        },
      ],
    },
  ];

[curItem.groupBy]You should try using reduce : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce

return Object.values(permissions.reduce((curObj, curItem) => { 
  if(!curObj.hasOwnProperty(curItem.groupBy)){
    curObj[curItem.groupBy] = { 
      label: curItem.label, 
      icon: curItem.icon, 
      children: [] 
    };
  }
  curObj[curItem.groupBy].children.push({ label: curItem.label });
  return curObj;
}, {}));

You can write something like:

const output = []

permissions.forEach(obj => {
  const dest = output.find(target => target.label === obj.groupBy);

  if (!dest) {
    output.push({ label: obj.groupBy, icon: obj.icon, children: [ { label: obj.permission_name } ] })
  } else {
    dest.children.push({ label: obj.permission_name })
  }
})

You are basically creating a new array, mapping the original based on your requires.

You could first create a function to reduce the array into an object, like so:

const groupBy = (prop, list) => {
    return list.reduce((groups, item) => {
        const propVal = item[prop];
        const target = groups[propVal] ?? [];
        
        return { ...groups, [propVal]: [...target, item] };
    }, {});
};

Or shorter:

const groupBy = (prop, list) => list.reduce((groups, item) => ({ ...groups, [item[prop]]: [...groups[item[prop]] ?? [], item] }), {});

And then:

const permObj = groupBy('groiupBy', permissions);
// { User: [...], Batch: [...] }

Now you could just work with that object or continue by writing a second function:

const groupsToArray = (nameProp, groups) => Object.entries(groups).map((g) => ({ [nameProp]: g[0], data: g[1] }))

And use it:

const newPermList = groupsToArray('label', permObj);

which would leave you with an array of objects with the according labels and the children in the 'data' prop of each object.

Of course then you could still filter out or map to get rid of duplicate data that you dont need. But you get the idea.

You colud find distinct groupBy values and then iterate on this array to fill result array like:

 let permissions= [ { code: 'U00', permission_name: 'Read User', groupBy: 'User', icon: 'user', }, { code: 'U01', permission_name: 'Create User', groupBy: 'User', icon: 'user', }, { code: 'B00', permission_name: 'Read Batch', groupBy: 'Batch', icon: 'user', }, { code: 'B01', permission_name: 'Create Batch', groupBy: 'Batch', icon: 'user', }, { code: 'B10', permission_name: 'Update Batch', groupBy: 'Batch', icon: 'user', }, ]; let groups = [...new Set(permissions.map(({groupBy})=>groupBy))]; let result = []; for (let i = 0; i < groups.length; i++){ let res = {}; res.label = groups[i]; res.icon = permissions.filter(x => x.groupBy === groups[i])[0].icon; res.children = []; let arrayOfGroup = permissions.filter(x => x.groupBy === groups[i]); for (let j = 0; j < arrayOfGroup.length; j ++){ let child = {}; child.label = arrayOfGroup[j].permission_name; res.children.push(child); } result.push(res); } console.log(result);

First step - get filtered necessary groupBy values.

Second step - mapping through filtered groupBy values and create a new array of objects based on your requirements.

 const permissions = [ { code: 'U00', permission_name: 'Read User', groupBy: 'User', icon: 'user', }, { code: 'U01', permission_name: 'Create User', groupBy: 'User', icon: 'user', }, { code: 'B00', permission_name: 'Read Batch', groupBy: 'Batch', icon: 'user', }, { code: 'B01', permission_name: 'Create Batch', groupBy: 'Batch', icon: 'user', }, { code: 'B10', permission_name: 'Update Batch', groupBy: 'Batch', icon: 'user', }, ]; const groups = [...new Set(permissions.map(({ groupBy }) => groupBy)) ]; const result = groups.map(groupName => ({ value: permissions.find(permission => permission.groupBy === groupName).groupBy, icon: permissions.find(permission => permission.icon === groupName.toLowerCase())?.icon, children: permissions.filter(permission => permission.groupBy === groupName).map(n => ({ value: n.permission_name })), })); const output = JSON.parse(JSON.stringify(result)); // For removing undefined keys. console.log(output);

You can use Array.prototype.reduce to alter the permissions Array the way you'll like.

 let permissions = [{ code: 'U00', permission_name: 'Read User', groupBy: 'User', icon: 'user', }, { code: 'U01', permission_name: 'Create User', groupBy: 'User', icon: 'user', }, { code: 'B00', permission_name: 'Read Batch', groupBy: 'Batch', icon: 'user', }, { code: 'B01', permission_name: 'Create Batch', groupBy: 'Batch', icon: 'user', }, { code: 'B10', permission_name: 'Update Batch', groupBy: 'Batch', icon: 'user', } ]; let results = permissions.reduce(function(accumulator, current) { let previousPermission = accumulator.find(function(el){ return el.label === current.groupBy }); if(.previousPermission){ return accumulator:concat({ label. current,groupBy: icon. current,icon: children: [{ label. current;permission_name }] }). } else { let permissionIndex = accumulator.findIndex(item => { return item.label === previousPermission;label; }). previousPermission = {..,previousPermission: children. [...previousPermission,children: { label. current;permission_name } ] } accumulator[permissionIndex] = previousPermission; return accumulator, } }; []). console;log(results);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM