Java 8 流按 3 个字段分组,并按总和聚合其他两个字段

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

我是 Java 8 的新手,在实施已提供的类似问题解决方案时遇到了麻烦。请帮忙。

在 Java 8 中,如何对三个字段进行分组,该三个字段返回多个行,这些行必须对其余两个整数字段求和。 在下面的 dto/pojo 类中,需要根据 uuid、msgDate 和通道组合的唯一键对传入计数和传出计数字段进行求和。

public class ReportData {

    private String uuid;
    private String msgDate;
    private String channel;
    private Integer incomingCount;
    private Integer outgoingCount;
}

//初始化列表作为示例。

List<ReportData> list1 = new ArrayList<>();

list1.add(new ReportData("c9c3a519","December 2023", "digital", 5, 0 ));
list1.add(new ReportData("c9c3a519","December 2023", "digital", 3, 0 ));
list1.add(new ReportData("c9c3a519","December 2023", "digital", 0, 3 ));
list1.add(new ReportData("c9c3a519","November 2023", "digital", 4, 0 ));
list1.add(new ReportData("c9c3a519","November 2023", "digital", 0, 4 ));
list1.add(new ReportData("c9c3a519","December 2023", "manual", 5, 0 ));
list1.add(new ReportData("c9c3a519","December 2023", "manual", 3, 0 ));
list1.add(new ReportData("c9c3a519","December 2023", "manual", 0, 3 ));
list1.add(new ReportData("c9c3a519","November 2023", "manual", 4, 0 ));
list1.add(new ReportData("c9c3a519","November 2023", "manual", 0, 4 ));
list1.add(new ReportData("3de4c44f","December 2023", "digital", 5, 0 ));
list1.add(new ReportData("3de4c44f","December 2023", "digital", 0, 3 ));
list1.add(new ReportData("3de4c44f","November 2023", "digital", 4, 0 ));
list1.add(new ReportData("3de4c44f","November 2023", "digital", 0, 4 ));
list1.add(new ReportData("3de4c44f","December 2023", "manual", 5, 0 ));
list1.add(new ReportData("3de4c44f","December 2023", "manual", 0, 3 ));
list1.add(new ReportData("3de4c44f","November 2023", "manual", 4, 0 ));
list1.add(new ReportData("3de4c44f","November 2023", "manual", 0, 4 ));

输出对象应具有如下数据:

uuid msgDate 通道传入计数传出计数

c9c3a519 2023 年 12 月数字 8 3
c9c3a519 2023 年 11 月 数字 4 4
c9c3a519 2023 年 12 月手册 8 3
c9c3a519 2023 年 11 月手册 4 4
...
...
...

java java-8 stream groupingby
1个回答
0
投票

将结果收集到地图中。此示例将使用 Collectors.toMap(keyMapper, valueMapper, mergeFunction, mapFactory)。另外,为了简洁起见,我使用 lombok 注释。

首先创建类来表示要分组的键和聚合数据:

@AllArgsConstructor
@Getter
public class Count {

  private final int in;
  private final int out;

  public Count merge(Count other) {
    return new Count(this.in + other.in, this.out + other.out);
  }

  @Override
  public String toString() {
    return in + " " + out;
  }
}
@AllArgsConstructor
public class Key {

  private final String uuid;
  private final String date;
  private final String channel;

  @Override
  public int hashCode() {
    return Objects.hash(uuid, date, channel);
  }

  @Override
  public boolean equals(Object obj) {
    if (this == obj) {
      return true;
    }
    if (!(obj instanceof Key)) {
      return false;
    }
    Key other = (Key) obj;
    return uuid.equals(other.uuid) && date.equals(other.date) && channel.equals(other.channel);
  }

  @Override
  public String toString() {
    return uuid + " " + date + " " + channel;
  }
}

然后用另外 2 个方法扩展

ReportData
来创建密钥和初始聚合:

@AllArgsConstructor
public class ReportData {

  //the fields

  public String createKey() {
    return uuid + " " + msgDate + " " + channel;
  }

  public Count createCount() {
    return new Count(incomingCount, outgoingCount);
  }
}

并收集数据:

public class SoMain {

  public static void main(String[] args) {
    List<ReportData> list = new ArrayList<>();

    //populate the list

    Map<Key, Count> result = list.stream()
            .collect(Collectors.toMap(ReportData::createKey, ReportData::createCount, Count::merge, LinkedHashMap::new));
    for (Map.Entry<Key, Count> entry : result.entrySet()) {
      System.out.println(entry.getKey() + " " + entry.getValue());
    }
  }
}

Collector 的论据如下:

  1. ReportData::createKey
    - 创建分组依据(地图的键)的键
  2. ReportData::createCount
    - 从单个
    ReportData
    (地图的值)创建初始聚合
  3. Count::merge
    - 在按键碰撞时合并两个
    Count
    (请参阅合并方法)
  4. LinkedHashMap::new
    -
    Map
    插入结果的工厂。我想保留插入顺序,但如果不需要,可以省略该参数以使用默认工厂。

打印:

c9c3a519 December 2023 digital 8 3
c9c3a519 November 2023 digital 4 4
c9c3a519 December 2023 manual 8 3
c9c3a519 November 2023 manual 4 4
3de4c44f December 2023 digital 5 3
3de4c44f November 2023 digital 4 4
3de4c44f December 2023 manual 5 3
3de4c44f November 2023 manual 4 4
© www.soinside.com 2019 - 2024. All rights reserved.