Java Stream groupingBy где ключ является элементом в подсписке - PullRequest
0 голосов
/ 04 июня 2018

У меня есть класс с именем Food:

public class Food {
    private Collection<FoodToFoodGroup> foodToFoodGroups;
    //getters and setters
}

И FoodToFoodGroup выглядит следующим образом:

public class FoodToFoodGroup {
    private Food food;
    private FoodGroup foodGroup;
    //getters and setters
}

Наконец, каждый FoodGroup имеет имя:

public class FoodGroup {
    private String name;
    //getters and setters
}

Все эти классы являются объектами, отображаемыми через Hibernate.Я получаю коллекцию всех Food сущностей в базе данных с вызовом foodRepository.findAll(), и я пытаюсь сгруппировать все Food экземпляры по имени их FoodGroup, чтобы в итоге получить Map<String, Collection<Food>>.Я пытался сделать это через Stream API, но не могу придумать способ сделать это с помощью коллектора Collectors.groupingBy.

Map<String, Collection<Food>> foodsByFoodGroupName = 
    foodRepository.findAll().stream()
        .collect(Collectors.groupingBy(
            //what goes here?
        ));

Обратите внимание, что Food может быть в несколькихFoodGroup с, поэтому мне понадобятся любые Food с несколькими FoodGroup с, которые будут отображаться в нескольких Collection с в результате Map.Возможно ли это с помощью Stream API и Collectors.groupingBy()?

Пример

Если у меня есть следующие продукты:

Food: Pimento Cheese
    - FoodToFoodGroups: [
        - FoodGroup: cheese,
        - FoodGroup: dairy
      ]
Food: Chocolate Milk
    - FoodToFoodGroups: [
        - FoodGroup: milk,
        - FoodGroup: dairy
      ]

Я бы хотелПолучившийся Map будет выглядеть так:

Key: cheese
    - Collection<Food>: [Pimento Cheese]
Key: milk
    - Collection<Food>: [Chocolate Milk]
Key: dairy
    - Collection<Food>: [Pimento Cheese, Chocolate Milk]

Ответы [ 2 ]

0 голосов
/ 04 июня 2018

Я не думаю, что groupingBy - это то, что вам нужно, поскольку он не предназначен для размещения одного и того же элемента в нескольких группах.

Для не совсем функционального решения, использующего потоки, вы могли быплоское сопоставление каждого Food с набором записей foodGroupToFood, затем добавление всех пар на карту с помощью BiConsumer.

BiConsumer<Map<FoodGroup, Set<Food>>, Map.Entry<FoodGroup, Food>> addEntryToMapOfSets = (map, entry) -> {
    if (map.containsKey(entry.key()))
        map.get(entry.key()).add(entry.value());
    else
        foodGroupToFoods.put(entry.key(), Stream.of(entry.value()).collect(Collectors.toSet()))
};
Map<String, Collection<Food>> foodGroupToFoods = new HashMap<>();
foods.stream()
  .flatMap(food -> food.getFoodToFoodGroup().stream()
       .collect(Collectors.toMap(pair -> pair.foodGroup, pair -> pair.food))
       .entrySet())
  .forEach(entry -> addEntryToMapofSets(foodGroupToFoods, entry));

Отказ от ответственности: я не писал на Java впока, пожалуйста, исправьте мое использование Streams API, если оно требует исправленияИзменить: Это, вероятно, сложнее, чем нужно.

0 голосов
/ 04 июня 2018

это то, что вы ищете

foodRepository.findAll().stream()
     .map(Food::getFoodToFoodGroup)
     .flatMap(Collection::stream)
     .collect(Collectors.groupingBy(
         f -> f.getFoodGroup().getName(),
         HashMap::new,
         Collectors.mapping(FoodToFoodGroup::getFood, Collectors.toList())));
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...