Home  >  Article  >  Java 8 stream group by 3 fields and aggregate other two fields by sum

Java 8 stream group by 3 fields and aggregate other two fields by sum

PHPz
PHPzforward
2024-02-22 13:46:06960browse

php editor Strawberry brings you questions and answers about grouping streams by 3 fields and aggregating the other two fields by the sum in Java 8. In Java programming, streams are a new way of processing collections. By using streams, data can be manipulated and processed more conveniently. This article will introduce in detail how to use the stream function of Java 8 to group by 3 fields and perform sum aggregation on the other two fields. Let’s explore this interesting question together!

Question content

I am new to java 8 and am having difficulty implementing the solutions that have been provided on similar questions. please help.

In java 8, how to group by three fields that returns multiple rows that must be summed over the remaining two integer fields. In the dto/pojo class below, the incoming count and outgoing count fields need to be summed based on the unique key of the uuid, msgdate, and channel combination.

public class reportdata {

    private string uuid;
    private string msgdate;
    private string channel;
    private integer incomingcount;
    private integer outgoingcount;
}

//Initialization list as an example.

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

The output object should contain the following data:

uuid msgdate Channel incoming count outgoing count

c9c3a519 December 2023 Number 8 3

c9c3a519 November 2023 Number 4 4

c9c3a519 December 2023 Manual 8 3

c9c3a519 November 2023 Manual 4 4

...

...

...

Solution

Collect the results into a map. This example will use Collectors.toMap(keyMapper, valueMapper, mergeFunction, mapFactory).

Also, for the sake of brevity, I use lombok annotations.

First create classes to represent the keys and aggregated data to be grouped:

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

Then extend reportdata with 2 more methods to create the key and initial aggregation:

@allargsconstructor
public class reportdata {

  //the fields

  public key createkey() {
    return new key(uuid, msgdate, channel);
  }

  public count createcount() {
    return new count(incomingcount, outgoingcount);
  }
}

and collect data:

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

The parameters of the collector are as follows:

  1. reportdata::createkey - Create the key to group by (key of the map)
  2. reportdata::createcount - Creates an initial aggregate from a single reportdata
  3. (the value of the map)
  4. count::merge - Merge two count (see merge method)
  5. when a key conflict occurs
  6. linkedhashmap::new - Factory for map used to insert results. I want to preserve the insertion order, but if not needed, the parameter can be omitted to use the default factory.

Print:

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

The above is the detailed content of Java 8 stream group by 3 fields and aggregate other two fields by sum. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:stackoverflow.com. If there is any infringement, please contact admin@php.cn delete