0

I have an array of objects like this:

const arrayOfObjects = [
{app: 'User', subpage: 'Dashboard', path: '/user/dashboard'}, 
{app: 'User', subpage: 'Profile', path: '/user/profile'},
{app: 'User', subpage: 'Settings', path: '/user/settings'},
{app: 'Library', subpage: 'Dashboard', path: '/library/dashboard'},
{app: 'Library', subpage: 'Settings', path: '/library/settings'},
{app: 'Material', subpage: 'Dashboard', path: '/material/dashboard'}]

I want an array of arrays...where each "sub-array" is an array of original objects from arrayOfObjects separated based upon only the app property (User, Library, Material). So, the new array should look like this:

newArray = [
     [{app: 'User', subpage: 'Dashboard', path: '/user/dashboard'}, 
      {app: 'User', subpage: 'Profile', path: '/user/profile'},
      {app: 'User', subpage: 'Settings', path: '/user/settings'}],
     [{app: 'Library', subpage: 'Dashboard', path: '/library/dashboard'},
      {app: 'Library', subpage: 'Settings', path: '/library/settings'}],
     [{app: 'Material', subpage: 'Dashboard', path: '/material/dashboard'}]
    ]

I've tried several things with both .map and .forEach, but the best I've done is convert the array of objects to an array of arrays...but without the grouping I need.

  • the problem with map is that you're going to end up with an output array that has the same number of elements as your input array, which you don't want here. The "right" array operator for this to be done as an "all-in-one" operation would be reduce, see https://stackoverflow.com/questions/14446511/most-efficient-method-to-groupby-on-an-array-of-objects – James Aug 17 '20 at 17:53

5 Answers5

0

We can use Array.find to check if there's already an element with the same value for app. If so, we can add to that array. If not, create a new array.

const arrayOfObjects = [
{app: 'User', subpage: 'Dashboard', path: '/user/dashboard'}, 
{app: 'User', subpage: 'Profile', path: '/user/profile'},
{app: 'User', subpage: 'Settings', path: '/user/settings'},
{app: 'Library', subpage: 'Dashboard', path: '/library/dashboard'},
{app: 'Library', subpage: 'Settings', path: '/library/settings'},
{app: 'Material', subpage: 'Dashboard', path: '/material/dashboard'}]

const newArray = []

arrayOfObjects.forEach(x => {
  const existing = newArray.find(y => y[0].app == x.app);
  if (existing) {
    existing.push(x);
  }
  else {
    newArray.push([x]);
  }
});

document.write(JSON.stringify(newArray))

Alternatively, using Array.reduce

const arrayOfObjects = [
{app: 'User', subpage: 'Dashboard', path: '/user/dashboard'}, 
{app: 'User', subpage: 'Profile', path: '/user/profile'},
{app: 'User', subpage: 'Settings', path: '/user/settings'},
{app: 'Library', subpage: 'Dashboard', path: '/library/dashboard'},
{app: 'Library', subpage: 'Settings', path: '/library/settings'},
{app: 'Material', subpage: 'Dashboard', path: '/material/dashboard'}]

const newArray = arrayOfObjects.reduce((a,b) => {
  const existing = a.find(x => x[0].app == b.app);
  if (existing) {
    existing.push(b);
  }
  else {
    a.push([b]);
  }
  return a;
}, []);

document.write(JSON.stringify(newArray));
Jannes Carpentier
  • 1,838
  • 1
  • 5
  • 12
0

Try Below

const arrayOfObjects = [
  {app: 'User', subpage: 'Dashboard', path: '/user/dashboard'}, 
  {app: 'User', subpage: 'Profile', path: '/user/profile'},
  {app: 'User', subpage: 'Settings', path: '/user/settings'},
  {app: 'Library', subpage: 'Dashboard', path: '/library/dashboard'},
  {app: 'Library', subpage: 'Settings', path: '/library/settings'},
  {app: 'Material', subpage: 'Dashboard', path: '/material/dashboard'}
]


let result = [];
let pushedItems = [];
arrayOfObjects.forEach((item) => {
  if (pushedItems.includes(item.app)) {
    return;
  }
  pushedItems.push(item.app);
  let subSet = arrayOfObjects.filter((filterItem) => {
    return item.app == filterItem.app;
  });
  if (subSet && subSet.length) {
    result.push(subSet);
  }
});
console.log(result);
Rahul Beniwal
  • 639
  • 4
  • 9
0

Create an object lookup for each app using array#reduce and then extract all values using Object.values().

const arrayOfObjects = [ {app: 'User', subpage: 'Dashboard', path: '/user/dashboard'}, {app: 'User', subpage: 'Profile', path: '/user/profile'}, {app: 'User', subpage: 'Settings', path: '/user/settings'}, {app: 'Library', subpage: 'Dashboard', path: '/library/dashboard'},{app: 'Library', subpage: 'Settings', path: '/library/settings'}, {app: 'Material', subpage: 'Dashboard', path: '/material/dashboard'}],
      result = Object.values(arrayOfObjects.reduce((r,o) => {
        r[o.app] = r[o.app] || [];
        r[o.app].push({...o});
        return r;
      },{}));
console.log(result);
Hassan Imam
  • 21,956
  • 5
  • 41
  • 51
0

You can get use for spread operator to get the keys and then use map along with filters

let allApp = [...new Set(arrayOfObjects.map(element=>element.app))];
let result = allApp.map(filters=>arrayOfObjects.filter(element=>element.app === filters))

console.log(result)
Anup
  • 589
  • 4
  • 8
0
const arrayOfObjects = [
        { app: 'User', subpage: 'Dashboard', path: '/user/dashboard' },
        { app: 'User', subpage: 'Profile', path: '/user/profile' },
        { app: 'User', subpage: 'Settings', path: '/user/settings' },
        { app: 'Library', subpage: 'Dashboard', path: '/library/dashboard' },
        { app: 'Library', subpage: 'Settings', path: '/library/settings' },
        { app: 'Material', subpage: 'Dashboard', path: '/material/dashboard' }]

    const generateArray = (array, ...args) => {
        const newArray = new Array;
        args.forEach(arguments => {
            newArray.push(array.filter(arr => {
                return arr.app.includes(arguments)
            }))
        })
        return newArray
    }

    const newArray = generateArray(arrayOfObjects, 'User', 'Library', 'Material')


    console.log(newArray)