Java 8按一对多分组

我想学习如何使用Java 8语法与流,并有点卡住。

当每个值都有一个键时,分组很容易。 但是如果我为每个值都有一个键列表并且仍然想用groupingBy对它们进行分类呢? 我是否必须将其分解为多个语句,或者可能有一些流魔术可以使其更简单。

这是基本代码:

List albums = new ArrayList(); Map<Artist, List> map = albums.stream().collect(Collectors.groupingBy(this::getArtist)); 

如果每个专辑只有一个艺术家,那么效果很好。 但我必须返回一个列表,因为专辑可以有很多艺术家。 专辑和艺术家当然用于说明,我有真实世界的类型..

可能有一个简单的解决方案,但我有一段时间没有找到它所以我呼吁这个网站代表的集体大脑来解决它。 :)如果不存在简单的解决方案,也欢迎使用复杂的解决方案。

在Album类中或作为以Album作为参数的实用程序方法:

 Artist getArtist(); // ok List getArtist(); // Not ok, since we now have many "keys" for every Album 

干杯,Mikael Grev

我想你是在追踪Collectors.mapping,它可以作为第二个参数传递给groupingBy

完整的例子

 import java.util.AbstractMap; import java.util.List; import java.util.Map; import static java.util.Arrays.asList; import static java.util.Map.Entry; import static java.util.stream.Collectors.*; public class SO { public static void main(String... args) { List albums = asList( new Album( asList( new Artist("bob"), new Artist("tom") ) ), new Album(asList(new Artist("bill"))) ); Map> x = albums.stream() .flatMap(album -> album.getArtist().stream().map(artist -> pair(artist, album))) .collect(groupingBy(Entry::getKey, mapping(Entry::getValue, toList()))); x.entrySet().stream().forEach(System.out::println); } static class Artist { private final String name; Artist(String name) { this.name = name; } public String toString() {return name;} } static class Album { private List artist; Album(List artist) { this.artist = artist; } List getArtist() { return artist; } } private static  AbstractMap.SimpleEntry pair(T t, U u) { return new AbstractMap.SimpleEntry(t,u); } } 

如果有人在寻找一个有效的例子,下面的内容应该是有用的。

 import java.util.AbstractMap; import java.util.AbstractMap.SimpleEntry; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.stream.Collectors; public class GroupSubject { public static void main(String[] args) { List items = Arrays.asList(new ContentItem("maths"), new ContentItem("science"), new ContentItem("social"), new ContentItem("chemistry"), new ContentItem("maths")); Map> x = (Map>) items.stream() .flatMap(item -> item.getSubjects().stream().map(subject -> pair(subject, item))) .collect(Collectors.groupingBy(e -> ((SimpleEntry) e).getKey(), Collectors .mapping(e -> ((SimpleEntry) e).getValue(), Collectors.toList()))); System.out.println(x); } private static  AbstractMap.SimpleEntry pair(T t, U u) { return new AbstractMap.SimpleEntry(t, u); } } class ContentItem { private List subjects = new ArrayList(); public ContentItem(String string) { subjects.add(string); } public List getSubjects() { return subjects; } public void setSubjects(List subjects) { this.subjects = subjects; } } 

使用Guava的Multimap,您可以拥有以下代码:

请注意,即使你有SetMultimap ,这也相当于Map>的预期结果。

我觉得这有点清楚;)

 SetMultimap artistToAlmbums = HashMultimap.create(); albums.stream().forEach(album -> { album.getArtist().forEach(artist -> artistToAlmbums.put(artist, album)); });