Eduardo Ronaldo
Eduardo Ronaldo

Reputation: 63

Group and sum data from a list of objects while preserving the insertion order

I have a list of DijkstraWays objects:

List<DijkstraWays> dijkstraWaysList= ...

DijkstraWays has the following attributes and getters:

class DijkstraWays {
    String name;
    Double cost;

    public String getName() {
        return name;
    }

    public Double getCost() {
        return cost;
    }
}

I need to group this list by name and make the sum of cost. For this, I used the following code:

Map<String, Double> result = dijkstraWaysList.stream()              
             .collect(Collectors.groupingBy(DijkstraWays::getName, 
                      Collectors.summingDouble(DijkstraWays::getCost)));

This code works, but it does not preserve the order of insertion of the elements in djkstraWaysList list. This is because Collectors.groupingBy returns a Map / HashMap, and this type does not preserve insertion orders.

How can I use Collectors.groupingBy and Collectors.summingDouble preserving the insertion order of the djkstraWaysList list? I found several examples on the internet where the result is transformed into a LinkedHashMap, which preserves this, but in none of them is it possible to insert the Collectors.summingDouble. Example:

dijkstraWays.stream()
            .collect(Collectors.groupingBy(DijkstraWays::getName,
                                LinkedHashMap::new,
                                Collectors.toList()));

I also need the sum of cost, but I can't use it together with groupby in these examples with LinkedHashMap.

Thanks.

Upvotes: 3

Views: 230

Answers (1)

Nowhere Man
Nowhere Man

Reputation: 19545

Supplier<Map> for LinkedHashMap should be inserted before the downstream collector (in this case Collectors.summingDouble) in Collectors.groupingBy:

public static Map<String, Double> totalCostGroupByName(List<DijkstraWays> ways) {
    return ways.stream()              
            .collect(Collectors.groupingBy(DijkstraWays::getName,
                    LinkedHashMap::new,
                    Collectors.summingDouble(DijkstraWays::getCost)
            ));
}

Test:

List<DijkstraWays> ways = Arrays.asList(
    new DijkstraWays("AB", 3),
    new DijkstraWays("AC", 5),
    new DijkstraWays("AD", 4),
    new DijkstraWays("BC", 3),
    new DijkstraWays("AC", 2),
    new DijkstraWays("AB", 6),
    new DijkstraWays("CD", 10)
);

System.out.println(totalCostGroupByName(ways)); // {AB=9.0, AC=7.0, AD=4.0, BC=3.0, CD=10.0}

Upvotes: 4

Related Questions