在 Java 8 中使用多个字段进行分组和计数

问题描述 投票:0回答:1

我在数据库中有一个 Person 表,关联的域类如下所示:

public class Person {   
    
    private String firstName;
    private String secondName;
    private String city;
    private String country;
    private int age;
    private int hits;
    
    // accessors
} 

数据库表将有同一个人的多行,我需要使用 java 8 聚合每行的点击量。

一个人由以下字段唯一标识: 名字, 第二个名字, 城市, 国家

我写了下面的逻辑,它给了我预期的结果

public void generateReport(List<PersonDTO> persons) {
        Map<String, Integer> personHitCount =
                persons
                        .stream()
                        .collect(Collectors.groupingBy(l -> getPersonKey(l), Collectors.summingInt(Person::getHits)));

        List<Person> reportRecords =
                persons
                        .stream().collect(Collectors.toMap(l -> getPersonKey(l), Function.identity(), (o1, o2) -> o1))
                        .entrySet()
                        .stream()
                        .filter(e -> personHitCount.containsKey(e.getKey()))
                        .map(e -> transform(e.getValue(), personHitCount.get(e.getKey())))
                        .collect(Collectors.toList());

        reportRecords.stream().forEach(System.out::println);
  }

private Person transform(Person personDTO, int count) {
    return new Person(
            personDTO.getFirstName(),
            personDTO.getSecondName(),
            personDTO.getCity(),
            personDTO.getCountry(),
            personDTO.getAge(),
            count);
}

private String getPersonKey(Person person) {
    return new StringJoiner("-")
            .add(person.getFirstName())
            .add(person.getSecondName())
            .add(person.getCity())
            .add(person.getCountry())
            .toString();
}

我不确定这是否是一种好的且高效的方法,因为我在人员列表上循环了两次。请您提出对此代码的任何改进或更好的方法。

java java-8 functional-programming stream java-stream
1个回答
0
投票

您可以通过首先按 Person 而不是 String 键进行分组来改进流,然后迭代映射的条目以将每个键和值转换为具有聚合点击数的 Person。

public void generateReport2(List < Person > persons) {
        List < Person > reportRecords =
                persons.stream()
                .collect(Collectors.groupingBy(Function.identity(), Collectors.summingInt(Person::getHits)))
                .entrySet().stream()
                .map(e - > transform(e.getKey(), e.getValue()))
                .collect(Collectors.toList());

        reportRecords.stream().forEach(System.out::println);
}
© www.soinside.com 2019 - 2024. All rights reserved.