Search code examples
javalistfilterjava-stream

Summarize data with Java streams


Is it possible to summarize values with streams? For example, I have a class Dataset that divides a csv file for me into lines that contain values:

{customer=Max , articlenr=1234, paid=12}
{customer=Lisa , articlenr=21, paid=20}
{customer=Max , articlenr=19, paid=100}

Now I want to create a List with a Stream which gives me a list of my customers back(no other values), sorted by the sum what they have ever paid (in this example Max has paid 112 and Lisa 20). So I would expect getting Max first in the List and the Lisa.


Solution

  • Collect the sum of paid to a Map<String, Integer>, then stream the entries, sorting them in reverse order by paid, then collect the keys to a List.

    List<MyClass> records; // your list
    
    List<String> customers = records.stream()
            .collect(groupingBy(MyClass::getCustomer, Collectors.summingInt(MyClass::getPaid)))
            .entrySet().stream()
            .sorted(Map.Entry.<String, Integer>comparingByValue().reversed())
            .map(Map.Entry::getKey)
            .collect(toList());
    

    Here is a complete working example in Java 23.

    record Payment( String name , int amount ) { }
    
    List < Payment > payments =
            List.of (
                    new Payment ( "Max" , 12 ) ,
                    new Payment ( "Lisa" , 20 ) ,
                    new Payment ( "Max" , 100 )
            );
    List < String > namesSortedByPaymentTotal =
            payments
                    .stream ( )
                    .collect ( groupingBy ( Payment :: name , Collectors.summingInt ( Payment :: amount ) ) )
                    .entrySet ( ).stream ( )
                    .sorted ( Map.Entry. < String, Integer > comparingByValue ( ).reversed ( ) )
                    .map ( Map.Entry :: getKey )
                    .toList ( );
    
    namesSortedByPaymentTotal.forEach ( System.out :: println );
    

    When run:

    Max
    Lisa
    

    To verify our work, modify that code.

    payments
            .stream ( )
            .collect ( groupingBy ( Payment :: name , Collectors.summingInt ( Payment :: amount ) ) )
            .entrySet ( ).stream ( )
            .sorted ( Map.Entry. < String, Integer > comparingByValue ( ).reversed ( ) )
            .forEach ( System.out :: println );
    
    Max=112
    Lisa=20