使用Java Streams按Collection属性分组

时间:2018-10-25 08:33:34

标签: java java-8 java-stream

我有一个包含字符串集合的对象,比方说一个人说的语言。

public class Person {
   private String name;
   private int age;
   private List<String> languagesSpoken;

   // ...
}

现在,创建一些这样的实例...

Person p1 = new Person("Bob", 21, Arrays.asList("English", "French", "German"));
Person p2 = new Person("Alice", 33, Arrays.asList("English", "Chinese", "Spanish"));
Person p3 = new Person("Joe", 43, Arrays.asList("English", "Dutch", "Spanish", "German"));

//put them in list
List<Person> people = Arrays.asList(p1,p2,p3);

...我想拥有的是Map<String, List<Person>>,每种语言都列出说该语言的人:

["English" -> [p1, p2, p3],
 "German"  -> [p1, p3],
 etc. ]

当然,可以通过命令式命令轻松进行编程,但是如何使用Java Streams来实现此功能呢?我已经尝试过类似people.stream.collect(groupingBy(Person::getLanguagesSpoken))的方法,但是那当然给了我Map<List<String>, List<Person>>。我可以找到的所有示例都在基元或字符串上使用groupingBy

2 个答案:

答案 0 :(得分:25)

您可以将Person实例分为成对的语言和Person(使用flatMap),然后根据需要将它们分组:

Map<String, List<Person>> langPersons =
    people.stream()
          .flatMap(p -> p.getLanguagesSpoken()
                         .stream()
                         .map(l -> new SimpleEntry<>(l,p)))
          .collect(Collectors.groupingBy(Map.Entry::getKey,
                                         Collectors.mapping(Map.Entry::getValue,
                                                            Collectors.toList())));

答案 1 :(得分:3)

这也可以不使用流而仍然使用Java-8新功能。

bt-presence