简体   繁体   English

使用自定义收集器的 Java 8 分组?

[英]Java 8 grouping using custom collector?

I have the following class.我有以下课程。

class Person {

    String name;
    LocalDate birthday;
    Sex gender;
    String emailAddress;

    public int getAge() {
        return birthday.until(IsoChronology.INSTANCE.dateNow()).getYears();
    }

    public String getName() {
        return name;
    }
}

I'd like to be able to group by age and then collect the list of the persons names rather than the Person object itself;我希望能够按年龄分组,然后收集人员姓名列表而不是 Person 对象本身; all in a single nice lamba expression.一切都在一个漂亮的lamba表达中。

To simplify all of this I am linking my current solution that store the result of the grouping by age and then iterates over it to collect the names.为了简化所有这些,我链接了我当前的解决方案,该解决方案存储按年龄分组的结果,然后对其进行迭代以收集名称。

ArrayList<OtherPerson> members = new ArrayList<>();

members.add(new OtherPerson("Fred", IsoChronology.INSTANCE.date(1980, 6, 20), OtherPerson.Sex.MALE, "fred@example.com"));
members.add(new OtherPerson("Jane", IsoChronology.INSTANCE.date(1990, 7, 15), OtherPerson.Sex.FEMALE, "jane@example.com"));
members.add(new OtherPerson("Mark", IsoChronology.INSTANCE.date(1990, 7, 15), OtherPerson.Sex.MALE, "mark@example.com"));
members.add(new OtherPerson("George", IsoChronology.INSTANCE.date(1991, 8, 13), OtherPerson.Sex.MALE, "george@example.com"));
members.add(new OtherPerson("Bob", IsoChronology.INSTANCE.date(2000, 9, 12), OtherPerson.Sex.MALE, "bob@example.com"));

Map<Integer, List<Person>> collect = members.stream().collect(groupingBy(Person::getAge));

Map<Integer, List<String>> result = new HashMap<>();

collect.keySet().forEach(key -> {
            result.put(key, collect.get(key).stream().map(Person::getName).collect(toList()));
});

Current solution当前解决方案

Not ideal and for the sake of learning I'd like to have a more elegant and performing solution.不理想,为了学习,我想要一个更优雅和更高效的解决方案。

When grouping a Stream with Collectors.groupingBy , you can specify a reduction operation on the values with a custom Collector .使用Collectors.groupingBy对 Stream 进行分组时,您可以使用自定义Collector指定对值的归约操作。 Here, we need to use Collectors.mapping , which takes a function (what the mapping is) and a collector (how to collect the mapped values).在这里,我们需要使用Collectors.mapping ,它接受一个函数(映射是什么)和一个收集器(如何收集映射值)。 In this case the mapping is Person::getName , ie a method reference that returns the name of the Person, and we collect that into a List .在这种情况下,映射是Person::getName ,即返回 Person 名称的方法引用,我们将其收集到List

Map<Integer, List<String>> collect = 
    members.stream()
           .collect(Collectors.groupingBy(
               Person::getAge,
               Collectors.mapping(Person::getName, Collectors.toList()))
           );

You can use a mapping Collector to map the list of Person to a list of person names :您可以使用mapping CollectorPerson列表mappingPerson列表:

Map<Integer, List<String>> collect = 
    members.stream()
           .collect(Collectors.groupingBy(Person::getAge,
                                          Collectors.mapping(Person::getName, Collectors.toList())));

You can also use Collectors.toMap and provide mapping for key, value and merge function(if any).您还可以使用 Collectors.toMap 并提供键、值和合并函数(如果有)的映射。

Map<Integer, String> ageNameMap = 
    members.stream()
            .collect(Collectors.toMap(
              person -> person.getAge(), 
              person -> person.getName(), (pName1, pName2) -> pName1+"|"+pName2)
    );

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

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