Java Stream groupingBy其中key是子列表中的元素

时间:2018-06-04 15:11:18

标签: java java-stream

我有一个名为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中的{1}}。这可以通过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 :(得分:1)

是你正在寻找的

foodRepository.findAll().stream()
     .map(Food::getFoodToFoodGroup)
     .flatMap(Collection::stream)
     .collect(Collectors.groupingBy(
         f -> f.getFoodGroup().getName(),
         HashMap::new,
         Collectors.mapping(FoodToFoodGroup::getFood, Collectors.toList())));

答案 1 :(得分:0)

I don't think groupingBy is what you want here, since it is not designed for putting the same item in multiple groups.

For a not-purely-functional solution using streams, you could flat-map each Food to a foodGroupToFood entry set, then add all of the pairs to a map using a 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));

Disclaimer: I haven't written in Java in a while, please correct my usage of Streams API if it needs correction. Edit: This is probably more complicated than it needs to be.