Home > front end >  Group by list of string / list of enum
Group by list of string / list of enum

Time:11-25

I have list of object like this:

enum TypeOfMeal {
  Breakfast,
  Dinner,
  Supper
}

interface Dish {
  name: string,
  category: TypeOfMeal[],
}

const dishes: Dish[] = [
  {
    name: 'Burger',
    category: [TypeOfMeal.Breakfast, TypeOfMeal.Dinner]
  },
  {
    name: 'Chips',
    category: [TypeOfMeal.Supper]
  },
  {
    name: 'Cereal with milk',
    category: [TypeOfMeal.Breakfast]
  }
];

I want groupped my dishes by category, so i want this output:

{
  'Breakfast': [
    {
      name: 'Burger',
      category: ['Breakfast', 'Dinner']
    },
    {
      name: 'Cereal with milk',
      category: ['Breakfast']
    }
  ],
  'Dinner': [
    {
      name: 'Burger',
      category: ['Breakfast', 'Dinner']
    },
  ],
  'Supper': [
    {
      name: 'Chips',
      category: ['Supper']
    },
  ],
};

CodePudding user response:

Something like this:

function groupBy<T>(
  getKeys: (item: T) => (string | number | symbol)[],
  items: T[]
): Record<string | number | symbol, T[]> {
  const result: Record<string | number | symbol, T[]> = {};

  for (const item of items) {
    for (const key of getKeys(item)) {
      if (!result[key]) {
        result[key] = [];
      }

      result[key].push(item);
    }
  }

  return result;
}

groupBy((dish) => dish.category, dishes);

CodePudding user response:

Disclaimer

StackOverflow isn't meant to provide freelance programming, it's more about teaching and learning :)


What you need

Therefore, here's the tools you need:

  1. Documentation for Array.prototype.reduce()
  2. Documentation for Spread syntax (...)
    (more specifically, the sections "Spread in array literals" and "Spread in object literals")
  3. Documentation for the Nullish coalescing operator (??)
    (not really necessary, but it's always good to know)

What you want

And just in case, here's the answer you want:

dishes.reduce(
  (res, dish) => dish.category.reduce((acc, meal) => ({ ...acc, [TypeOfMeal[meal]]: [...(acc[TypeOfMeal[meal]] ?? []), dish] }), res),
  {} as { [key: string]: Dish[] },
)

I reckon you may actually be better off keeping the keys of your resulting set as TypeOfMeal rather than the string representation of the enum.
Just have them "translate" when you need to present them!

dishes.reduce(
  (res, dish) => dish.category.reduce((acc, meal) => ({ ...acc, [meal]: [...(acc[meal] ?? []), dish] }), res),
  {} as { [key in TypeOfMeal]: Dish[] },
)
  • Related