Группировать по списку строк / списку перечислений

#angular #typescript #group-by

Вопрос:

У меня есть список объектов, подобных этому:

 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]
  }
];
 

Я хочу сгруппировать мой dishes по category , поэтому я хочу этот вывод:

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

 

Ответ №1:

Что-то вроде этого:

 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 resu<
}

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

Ответ №2:

Отказ от ответственности

StackOverflow не предназначен для обеспечения внештатного программирования, это больше касается преподавания и обучения 🙂


Что вам нужно

Поэтому вот инструменты, которые вам нужны:

  1. Документация для Array.prototype.reduce()
  2. Документация для расширенного синтаксиса ( ... )
    (более конкретно, разделы «Распространение в литералах массива» и «Распространение в литералах объектов»)
  3. Документация для нулевого объединяющего оператора ( ?? )
    (на самом деле это не обязательно, но всегда полезно знать)

Что вы хотите

И на всякий случай, вот ответ, который вы хотите:

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

Я думаю, вам действительно может быть лучше сохранить ключи вашего результирующего набора, TypeOfMeal а не string представление enum .
Просто попросите их «перевести», когда вам нужно их представить!

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