Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java 8 lambda adding to a list in a Hashmap, in a Hashmap

I have a List<POJO> that I want to extract data from and the variables I'm interested in are:

  • Environment: String
  • Application: String
  • Throughput: Double

There are 7 Environment objects and each Environment has 18 Application objects, which each have multiple values.

I'm trying to iterate over the List<POJO> and store these values in a Hashmap<Environment.ToString, Hashmap<Applications.ToString, List<Double>>

I'm trying to use Java 8's Lambda features; my code so far:

private HashMap<String, List<BigDecimal>> appMap = new HashMap<String, List<BigDecimal>>();
private HashMap<String, HashMap> envMap = new HashMap<String, HashMap>();

for(POJO chartModel: List<POJO>) {
    appMap.computeIfAbsent(chartModel.getName(), v -> new ArrayList<BigDecimal>())
          .add(BigDecimal.valueOf(chartModel.getThroughput()));
    envMap.put(chartModel.getEnvironment(), appMap);
}

Firstly, is there a shorthand way to iterate over the List inside the inner Map using Java8?

Secondly, my code isn't quite right, so currently the map adds all the Throughput values to its Application key, so I end up with 18 keys with a list of values.

What I need it to do is in my envMap I should have 7 Environment objects, with each having its 18 Application objects and values, so there would be 126 Application objects in total. Can this be achieved the way I'm attempting it, is there a Lambda way to achieve this?

like image 360
JTK Avatar asked Dec 25 '22 08:12

JTK


2 Answers

You need to use 2 grouping by operations: the first one groups according to the environment and the second one groups according to the name. Finally, you need to map each values to the BigDecimal value of their throughput.

Assuming pojo is a List<POJO>:

Map<String, Map<String, List<BigDecimal>>> result =
    pojo.stream()
        .collect(Collectors.groupingBy(
            POJO::getEnvironment,
            Collectors.groupingBy(
                POJO::getName,
                Collectors.mapping(p -> BigDecimal.valueOf(p.getThroughput()), Collectors.toList())
            )
        ));
like image 125
Tunaki Avatar answered Dec 28 '22 05:12

Tunaki


You are creating only one Map, appMap, which you are putting into envMap for every key. You obviously want to create a new Map for each distinct key and you already know the right tool, computeIfAbsent. But you should also mind the “diamond operator”. While not being a new Java 8 feature, your code will clearly benefit from removing the repetitions of the type parameters. Putting it all together, the operation will look like:

HashMap<String, Map<String, List<BigDecimal>>> envMap = new HashMap<>();
for(POJO chartModel: list) {
    envMap.computeIfAbsent(chartModel.getEnvironment(), env -> new HashMap<>())
        .computeIfAbsent(chartModel.getName(), name -> new ArrayList<>())
        .add(BigDecimal.valueOf(chartModel.getThroughput()));
}

You can also express the same logic using the Stream API, as shown by Tunaki, but you don’t need to.

like image 29
Holger Avatar answered Dec 28 '22 07:12

Holger