Home > Blockchain >  How to stream a Map of Map
How to stream a Map of Map

Time:10-04

I have two Maps received as parameter in the function below...

 private static BigDecimal getTotalOrcamentoARealizarBySKUCanal(Map<SKUIdCanalIdDTO, Map<LocalDate, BigDecimal>> factByMonth, Map<SKUIdCanalId, Map<LocalDate, Budget>> budgetByMonth) {

    }

What I need to do, is to check if the keys of the Map inside (LocalDate) doesn't contain in the other Map, just like I did in the other example below:

private static BigDecimal getValueBudgetUnrealized (Map<LocalDate, BigDecimal> factByMonth, Map<LocalDate, BudgetDTO> budgetByMonth, Measure measure) {
        return budgetByMonth.entrySet().stream()
                .filter(budget-> !factByMonth.containsKey(budget.getKey()))
                .map(budget-> budget.getValue().getValueByMeasure(measure))
                .reduce(BigDecimal.ZERO, BigDecimal::add);
    }

Well, I've been stuck with this, and I couldn't manage to solve this problem.

CodePudding user response:

You can do something like this to find the dates in the one map which are not in the other. You'll also need to do it the other way if you want to find all the discrepancies through this method.

List<LocalDate> datesInFactByMonthNotInBudgetByMonth = factByMonth.values().stream()
        .map(Map::keySet)
        .flatMap(Set::stream)
        .filter(localDateFromFactByMonth -> budgetByMonth.values().stream()
                .map(Map::keySet)
                .flatMap(Set::stream)
                .noneMatch(localDateFromFactByMonth::equals))
        .collect(Collectors.toList());

CodePudding user response:

In case if you want all entries from each nested map from budgetByMonth which doesn't have a matching in any of the maps contained within factByMonth to contribute the resulting BigDecimal value, firstly you can generate a Set of key which can be encountered in factByMonth and then check every entry from budgetByMonth against this set.

In order to flatten the data from the nested maps, you can use flatMap() operation, which expects a function that generates a new stream from every element of the pipeline.

That's how it might look like:

private static BigDecimal getTotalOrcamentoARealizarBySKUCanal(
    Map<SKUIdCanalIdDTO, Map<LocalDate, BigDecimal>> factByMonth,
    Map<SKUIdCanalId, Map<LocalDate, Budget>> budgetByMonth
) {
    Set<LocalDate> factByMonthKeys = factByMonth.values().stream()
        .flatMap(map -> map.keySet().stream())
        .collect(Collectors.toSet());
    
    return budgetByMonth.values().stream()
        .flatMap(map -> map.entrySet().stream())
        .filter(entry -> !factByMonthKeys.contains(entry.getKey()))
        .map(entry -> entry.getValue().`~ get BigDecimal from Budget object somehow ~`)
        .reduce(BigDecimal.ZERO, BigDecimal::add);
}

And in case if you want to reject the hole map from budgetByMonth if any of its keys is present within factByMonth, then you need to apply filter() before flattening the data.

private static BigDecimal getTotalOrcamentoARealizarBySKUCanal(
    Map<SKUIdCanalIdDTO, Map<LocalDate, BigDecimal>> factByMonth,
    Map<SKUIdCanalId, Map<LocalDate, Budget>> budgetByMonth
) {
    Set<LocalDate> factByMonthKeys = factByMonth.values().stream()
        .flatMap(map -> map.keySet().stream())
        .collect(Collectors.toSet());
    
    return budgetByMonth.values().stream()
        .filter(map -> map.keySet().stream().noneMatch(factByMonthKeys::contains))
        .flatMap(map -> map.entrySet().stream())
        .map(entry -> entry.getValue().`~ get BigDecimal from Budget object somehow ~`)
        .reduce(BigDecimal.ZERO, BigDecimal::add);
}
  • Related