Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java 8 Lambdas - How to Sum and Average from a stream

Tags:

java

lambda

Is it possible to sum and average and transform to a new object from a stream . I have an object

    public class Foo {
       private String code;
       private double price;
      ....
    }

Now I want to get the average and sum this object list ( sum price by code and average price by code as well)

 foos = Arrays.asList(
            new Foo("MTN" , 200 ),
            new Foo("MTN" , 210 ),
            new Foo("MTN" , 205 ),
            new Foo("OMT" , 300 ),
            new Foo("OMT" , 320 ),
            new Foo("OMT" , 310 ),
            new Foo("AAA" , 650 ),
            new Foo("AAA" , 680 ),
            new Foo("AAA" , 600 ));

I would then want to create a new Object (FooB

    public class FooB {
       private String code;
       private double total;
       private double average;
       ....
   }

This is what I have now it works but I go through the stream twice . I want a method where I can do this by going through the stream once .

 Map<String, Double> averagePrices = foos.stream()
            .collect(
                    Collectors.groupingBy(
                   Foo::getCode,Collectors.averagingDouble(Foo::getPrice)));



    Map<String, Double> totalPrices = foos.stream()
            .collect(
                    Collectors.groupingBy(
                            Foo::getCode,
                            Collectors.summingDouble(Foo::getPrice)));


    List<FooB > fooBs = new ArrayList<>();
    averagePrices.forEach((code, averageprice)-> {
        FooB fooB = new FooB (code , totalPrices.get(code)  , averageprice);
        fooBs.add(fooB );
    });

    fooBs.forEach(e -> System.out.println(e.toString()));

Is there a better way of doing this without repeating this . Thanks

like image 209
kenneth Chamisa Avatar asked Jun 14 '16 15:06

kenneth Chamisa


1 Answers

You could use DoubleSummaryStatistics to hold both results before mapping to FooB:

Map<String, DoubleSummaryStatistics> data = foos.stream()
                .collect(Collectors.groupingBy(Foo::getCode,
                                    Collectors.summarizingDouble(Foo::getPrice)));

List<FooB> fooBs = data.entrySet().stream()
        .map(e -> new FooB(e.getKey(), e.getValue().getSum(), e.getValue().getAverage()))
        .collect(toList());
like image 120
assylias Avatar answered Sep 19 '22 12:09

assylias