Home > Enterprise >  Group array of objects by multiple nested values
Group array of objects by multiple nested values

Time:09-12

I have an array of objects which presents tasks. These tasks are categorized (primary / secondary category).

let tasks = [
  {
    id: 1,
    name: 'Cleanup desk',
    primary_category: {
      id: 1,
      name: 'Indoor'
    },
    secondary_category: {
      id: 2,
      name: 'Surfaces'
    }
  },
  {
    id: 2,
    name: 'Cleanup office floors',
    primary_category: {
      id: 1,
      name: 'Indoor'
    },
    secondary_category: {
      id: 3,
      name: 'Ground'
    }
  },
  {
    id: 3,
    name: 'Water plants',
    primary_category: {
      id: 2,
      name: 'Outdoor'
    },
    secondary_category: {
      id: 3,
      name: 'Irrigation'
    }
  }
];

I now try to create a categories accordion in my frontend and therefore need to group my array differently. The structure should look like:

1) primary category 
   > secondary category 
      > tasks
   > secondary category 
      > tasks
2) primary category 
   > secondary category 
      > tasks

Therefore I'm trying to achieve a structure similar to this:

let tasks_categorized = [
  {
    id: 1,
    name: 'Indoor',
    secondary_categories: [
      {
        id: 2,
        name: 'Surfaces',
        tasks: [
          {
            id: 1,
            name: 'Cleanup desk'
          }
        ]
      },
      {
        id: 3,
        name: 'Ground',
        tasks: [
          {
            id: 2,
            name: 'Cleanup office floors'
          }
        ]
      }
    ]
  },
  {
    id: 2,
    name: 'Outdoor',
    secondary_categories: [
      {
        id: 3,
        name: 'Irrigation',
        tasks: [
          {
            id: 3,
            name: 'Water plants'
          }
        ]
      }
    ]
  }
];

I tried using groupBy by lodash but this does not allow grouping by multiple nested key-value pairs. Does anybody know an approach to solve this?

Thank you in advance!

CodePudding user response:

You could take a dynamic approach with an array of grouping data and keys for the nested arrays.

const
    tasks = [{ id: 1, name: 'Cleanup desk', primary_category: { id: 1, name: 'Indoor' }, secondary_category: { id: 2, name: 'Surfaces' } }, { id: 2, name: 'Cleanup office floors', primary_category: { id: 1, name: 'Indoor' }, secondary_category: { id: 3, name: 'Ground' } }, { id: 3, name: 'Water plants', primary_category: { id: 2, name: 'Outdoor' }, secondary_category: { id: 3, name: 'Irrigation' } }],
    groups = [
        [o => o, 'primary category'],
        [o => o.primary_category, 'secondary category'],
        [o => o.secondary_category, 'tasks']
    ],
    result = tasks.reduce((r, o) => {
        groups.reduce((parent, [fn, children]) => {
            const { id, name } = fn(o);
            let item = (parent[children] ??= []).find(q => q.id === id)
            if (!item) parent[children].push(item = { id, name });
            return item;
        }, r);
        return r;
    }, {})[groups[0][1]];

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

CodePudding user response:

might not be the cleanest solution, but this will work

const tasks = [{
    id: 1,
    name: "Cleanup desk",
    primary_category: {
      id: 1,
      name: "Indoor"
    },
    secondary_category: {
      id: 2,
      name: "Surfaces"
    }
  },
  {
    id: 2,
    name: "Cleanup office floors",
    primary_category: {
      id: 1,
      name: "Indoor"
    },
    secondary_category: {
      id: 3,
      name: "Ground"
    }
  },
  {
    id: 3,
    name: "Water plants",
    primary_category: {
      id: 2,
      name: "Outdoor"
    },
    secondary_category: {
      id: 3,
      name: "Irrigation"
    }
  }
];

let fixedCategories = [];
tasks.map((object) => {
  const categoryIndex = fixedCategories.findIndex(
    (category) => category.name === object.primary_category.name
  );
  if (categoryIndex >= 0) {
    const subCategoryIndex = fixedCategories[
      categoryIndex
    ].secondary_categories.findIndex(
      (subCategory) => subCategory.name === object.secondary_category.name
    );
    if (subCategoryIndex >= 0) {
      fixedCategories[categoryIndex].secondary_categories[
        subCategoryIndex
      ].tasks.push({
        id: object.id,
        name: object.name
      });
    } else {
      const subCategory = {
        name: object.secondary_category.name,
        id: object.secondary_category.id,
        tasks: [{
          id: object.id,
          name: object.name
        }]
      };
      fixedCategories[categoryIndex].secondary_categories.push(subCategory);
    }
  } else {
    const category = {
      name: object.primary_category.name,
      id: object.primary_category.id,
      secondary_categories: [{
        name: object.secondary_category.name,
        id: object.secondary_category.id,
        tasks: [{
          id: object.id,
          name: object.name
        }]
      }]
    };
    fixedCategories.push(category);
  }
  return fixedCategories;
});

console.log(fixedCategories);

  • Related