简体   繁体   English

Java流/收集:将具有多个字段的一项映射到多个键

[英]Java stream/collect: map one item with multiple fields to multiple keys

I have the following code that I'd like to try to write using the java collectors. 我有以下代码,我想尝试使用Java收集器编写。

Given 2 attributes (firstname and lastname) of a person, I'd like to get a map containing the unique firstname or lastname as a key, and the list of the corresponding persons. 给定一个人的2个属性(名字和姓氏),我想获得一张包含唯一的名字或姓氏作为键的地图,以及对应的人的列表。

Here's a set of data : 这是一组数据:

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);

Output (as expected) is the following : 输出(预期)如下:

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'}]

And the code to populate the map : 以及填充地图的代码:

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);
    }
}

I can't figure out how I can get either the firstname or the lastname as a key (not like in Group by multiple field names in java 8 ). 我不知道如何获取名字或姓氏作为键(这与java 8中的Group by Multiple field name不同 )。 Do I have to write my own collector? 我必须写我自己的收藏家吗?

You can use Stream.flatMap() and Collectors.groupingBy() with Collectors.mapping() : 您可以将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())));

This uses flatMap to expand all names (first and past) to their Person object and collects it afterwards. 这将使用flatMap将所有名称(名字和过去的名字)扩展到其Person对象,然后将其收集。

Alternatively using Java 9 or above you could use Collectors.flatMapping() : 或者使用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()))));

But I don't think that this is more readable. 但是我不认为这更具可读性。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM