我有一个包含以下字段的课程:
public class Item{
private String name;
private Long category;
private Set<Long> containers;
}
我需要做的就是
List<Item> items
变成
Map<Long/*categoryID*/, Set<Long/*Containers*/>>
使用Java 8 Stream API。
现在,我可以使用Itarable
和一些if
得到相同的结果,就像这样:
List<Item> items = getItems();
Iterator<Item> itemsIterator = items.iterator();
Map<Long/*categoryID*/, Set<Long/*Containers.ID*/>> containersByCategoryMap = new HashMap<>();
while (itemsIterator.hasNext()) {
Item item = itemsIterator.next();
Long category = item.getCategory();
Set<Long> containers = item.getContainers();
if (containersByCategoryMap.containsKey(category)) {
Set<Container> containersByCategory = containersByCategoryMap.get(category);
containersByCategory.addAll(containers);
} else {
Set<Container> containersByCategory = new HashSet<>(containers);
containersByCategoryMap.put(category, containersByCategory);
}
}
如何使用Stream API获得相同的结果?
我尝试了类似的方法,但是很明显我得到了重复的键异常,因为每个类别都有多个项目...
containersByCategoryMap = items.stream().collect(Collectors.toMap(item -> item.getCategory(), item -> item.getContainers()));
答案 0 :(得分:4)
自Java-9起,就有Collectors.flatMapping
:
Map<Long, Set<Long>> map = items.stream()
.collect(Collectors.groupingBy(
Item::getCategory,
Collectors.flatMapping(x -> x.getContainers().stream(), Collectors.toSet())));
没有Java-9,您可以这样做:
Map<Long, Set<Long>> result = items.stream()
.flatMap(x -> x.getContainers().stream().map(y -> new SimpleEntry<>(x.getCategory(), y)))
.collect(Collectors.groupingBy(
Entry::getKey,
Collectors.mapping(Entry::getValue, Collectors.toSet())));
您也可以使用Map#merge
进行此操作:
Map<Long, Set<Long>> map2 = new HashMap<>();
items.forEach(x -> map2.merge(
x.getCategory(),
x.getContainers(),
(left, right) -> {
left.addAll(right);
return left;
}));
答案 1 :(得分:1)
您可以使用带有合并功能的toMap
来处理键冲突,
Map<Long, Set<Long>> containersByCategoryMap = items.stream()
.collect(Collectors.toMap(Item::getCategory,
Item::getContainers,
(s1, s2) -> Stream.concat(s1.stream(), s2.stream()).collect(Collectors.toSet())));
答案 2 :(得分:0)
您可能还对使用Guava及其SetMultimap界面(比Map<?, Set<?>>
更易于使用)感兴趣。
如果您希望结果数据结构不可变,则可以使用ImmutableSetMultimap.flatteningToImmutableSetMultimap
,如下所示:
SetMultimap<Long, Long> multimap = items.stream()
.collect(ImmutableSetMultimap.flatteningToImmutableSetMultimap(
Item::getCategory, item -> item.getContainers().stream()
));