Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I get some statistics using java 8 stream with object list

I have a List<SqlResult>. I need to get a List<Result> from the aggregation of SqlResult. For example,

SqlResult(Input)

public class SqlResult{
  private String key1;
  private String key2;
  private Double val;
  // getters, setters and constructor

Result Data Class

public class Result{
  private String key1;
  private String key2;
  private Double avgVal;
  private Long   count;
  // getters, setters and constructor

I want get List like below, group by with key1, key2, count of members(count), average of val(avgVal) Below code throw NullPointerException.

public class Main 
{
  public static void main(String[] args) {
    List<SqlResult> listSqlResult = new ArrayList<>();
    listSqlResult.add(new SqlResult(a1,b1,123));
    listSqlResult.add(new SqlResult(a1,b1,10));
    listSqlResult.add(new SqlResult(a1,b1,23));
    listSqlResult.add(new SqlResult(a1,b2,3));
    listSqlResult.add(new SqlResult(a1,b2,73));
    listSqlResult.add(new SqlResult(a1,b2,15));
    listSqlResult.add(new SqlResult(a2,b1,43));
    listSqlResult.add(new SqlResult(a2,b1,19));
    listSqlResult.add(new SqlResult(a2,b1,15));
    listSqlResult.add(new SqlResult(a2,b2,38));
    listSqlResult.add(new SqlResult(a2,b2,73));
    listSqlResult.add(new SqlResult(a2,b2,15));

    List<Result> listResult = listSqlResult.stream
        .collect(groupingBy(SqlResult::getKey1,
                 groupingBy(SqlResult::getKey2))).values().stream()
        .map(e -> new Result(e.get(0).get(0).getKey1(), e.get(0).get(0).getKey2(),e.get(0).stream().mapToDouble(e::getValue).average(), e.get(0).stream().count()))
    .collect(Collectors.toList())
;

How can I get statistical results (average of val, count of member) using Java Stream API?

like image 340
Jeonghun Kim Avatar asked Sep 04 '26 23:09

Jeonghun Kim


1 Answers

The cause for your code failing is that you end up performing a Map.get with Integer key over a Map which during groupingBy was constructed with Strings in keyset. Hence the corresponding null value in lookup followed by an NPE.

It would be simpler if you could think of formulating your requirements into two steps. One, where you summarise the data that is in your hand. Other, where you map it to the desired result object of your choice.

With the help of existing Collectors.summarizing..., this could look as simple as the following:

Map<List<String>, DoubleSummaryStatistics> groupedStatistics = listSqlResult.stream()
        .collect(Collectors.groupingBy(sr -> Arrays.asList(sr.getKey1(), sr.getKey2()),
                Collectors.summarizingDouble(SqlResult::getVal)));

List<Result> results = groupedStatistics.entrySet().stream()
        .map(e -> new Result(e.getKey().get(0), e.getKey().get(1),
                e.getValue().getAverage(), e.getValue().getCount()))
        .collect(Collectors.toList());
like image 186
Naman Avatar answered Sep 06 '26 14:09

Naman



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!