当前位置: 首页 > 知识库问答 >
问题:

Java Stream/Collect:将一个具有多个字段的项映射到多个键

陶原
2023-03-14

下面是我想尝试使用java收集器编写的代码。

给定一个人的2个属性(firstname和lastname),我想获得一个包含唯一的firstname或lastname作为键的地图,以及相应的人的列表。

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

我不知道如何将firstname或lastname作为键(不像Java8中的Group by multiple field names)。我一定要写我自己的收藏家吗?

共有1个答案

双志强
2023-03-14

您可以将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将所有名称(first和past)展开到它们的person对象中,然后收集它。

或者使用Java9或更高版本,您可以使用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()))));

但我不认为这是更易读的。

 类似资料:
  • 我把这三门课分别放在不同的文件中 我有下面的映射器 这目前仅映射lastName并起作用,我想将Book中的作者字符串映射为 我怎么能这么做?我在MapStruct文档中找不到任何东西。

  • “想要解决方案B” 有什么办法可以做到这一点吗?

  • 我提到了用Mapstruct将多个源字段映射到同一类型目标字段的问题,但这没有帮助 我的rest资源类如下所示 我的实体类是源代码,如下所示: 我想在mapper类中用emailAdddress或devices或mobileNumbers映射源类中的地址,我尝试在mapper类中使用@AfterMapping和一个decorator类,但它没有帮助。 我有一个像这样的映射器类

  • 问题内容: 我正在尝试建立一个PostgreSQL表,该表具有两个指向另一个表中相同主键的外键。 运行脚本时出现错误 sqlalchemy.exc.AmbiguousForeignKeysError:无法确定关系Company.stakeholder的父/子表之间的联接条件- 有多个链接表的外键路径。指定“ foreign_keys”参数,提供这些列的列表,这些列应被视为包含对父表的外键引用。 那

  • 我有一个Kubernetes集群在运行,并且有多个服务在几个Pod前面。当我将each服务公开为LoadBalancer时,它会为公共使用创建一个唯一的endpoint。是否有一种方法可以将其配置为公开1个公共endpoint,然后使用过滤器根据请求路径将流量重定向到正确的Pod?例如,外部endpoint:www.common-domain/v1/api/ 服务1:/Account Pod 1:

  • 问题内容: 我有一个包含三个字段(所有字符串类型)的“报告”对象列表- 我有一个排序代码,就像 由于某种原因,我没有排序顺序。一个建议在字段之间放置空格,但是为什么呢? 你认为代码有什么问题吗? 问题答案: 你认为代码有什么问题吗? 是。为什么在比较它们之前将三个字段加在一起? 我可能会做这样的事情:(假设字段按照你希望对其进行排序的顺序)