我想尝试使用Java收集器编写以下代码。
给出一个人的2个属性(名字和姓氏),我想获取一个包含唯一的名字或姓氏作为键的地图,以及相应的人的列表。
这是一组数据:
Person person1 = new Person();
person1.setFirstName("john");
person1.setLastName("doe");
person1.setUserId("user1");
Person person2 = new Person();
person2.setFirstName("doe");
person2.setLastName("frank");
person2.setUserId("user2");
Person person3 = new Person();
person3.setFirstName("john");
person3.setLastName("wayne");
person3.setUserId("user3");
List<Person> personList = new ArrayList<>();
personList.add(person1);
personList.add(person2);
personList.add(person3);
(预期的)输出如下:
frank=[Person{userId='user2', firstName='doe', lastName='frank'}],
john=[Person{userId='user1', firstName='john', lastName='doe'}, Person{userId='user3', firstName='john', lastName='wayne'}],
doe=[Person{userId='user1', firstName='john', lastName='doe'}, Person{userId='user2', firstName='doe', lastName='frank'}],
wayne=[Person{userId='user3', firstName='john', lastName='wayne'}]
以及用于填充地图的代码:
Map<String, List<Person>> mapPersons = new HashMap<String, List<Person>>();
List<Person> listPersons;
for (Person p: personList) {
if (mapPersons.get(p.getFirstName()) == null) {
listPersons = new ArrayList<Person>();
listPersons.add(p);
mapPersons.put(p.getFirstName(), listPersons);
} else {
mapPersons.get(p.getFirstName()).add(p);
}
if (mapPersons.get(p.getLastName()) == null) {
listPersons = new ArrayList<Person>();
listPersons.add(p);
mapPersons.put(p.getLastName(), listPersons);
} else {
mapPersons.get(p.getLastName()).add(p);
}
}
我不知道如何获得名字或姓氏作为键(与Group by multiple field names in java 8中不同)。我必须写我自己的收藏家吗?
答案 0 :(得分:5)
您可以将Stream.flatMap()
和Collectors.groupingBy()
与Collectors.mapping()
一起使用:
Map<String, List<Person>> result = personList.stream()
.flatMap(p -> Stream.of(p.getFirstName(), p.getLastName()).map(n -> new AbstractMap.SimpleEntry<>(n, p)))
.collect(Collectors.groupingBy(Map.Entry::getKey, Collectors.mapping(Map.Entry::getValue, Collectors.toList())));
这使用flatMap
将所有名称(名字和过去的名字)扩展到其Person
对象,然后将其收集。
或者使用Java 9或更高版本,也可以使用Collectors.flatMapping()
:
Map<String, List<Person>> result = personList.stream()
.collect(Collectors.flatMapping(
p -> Stream.of(p.getFirstName(), p.getLastName()).map(n -> new AbstractMap.SimpleEntry<>(n, p)),
Collectors.groupingBy(Map.Entry::getKey,
Collectors.mapping(Map.Entry::getValue, Collectors.toList()))));
但是我不认为这更具可读性。