Search code examples
javaalgorithmjava-streamtreemap

Transform a map from daily data to weekly data in Java


I have a map of LocalDate and Integer with daily data. Now I want to create a new map with the weekly data, which means new map will contain the cumulative count when we sum up the integers which falls under previous entry and current entry. I am stuck in this. Can anyone please help me in designing an algorithm for this. I am new to Java Stream api, if it is doable using Stream API it will

Example data:
example data

In the image I have tried traversing the weeklyMap and then inside that traversed the dailyMap. But I am not sure how to make it possible in code(Java).

EDIT

Code snippet:

Map.Entry<LocalDate, Integer> prevEntry = null;
        boolean firstTime = true;
        for (Map.Entry<LocalDate, Integer> currEntry : weeklyMap.entrySet()) {
            if (firstTime) {
                prevEntry = currEntry;
                firstTime = false;
                if (weeklyMap.containsKey(currEntry.getKey())) {
                    weeklyMap.put(currEntry.getKey(), currEntry.getValue());
                }
            } else {
                for (Map.Entry<LocalDate, Integer> todayEntry : dailyMap.entrySet()) {
                    if (prevEntry.getKey().equals(todayEntry.getKey())) {
                        prevEntry.setValue(todayEntry.getValue());
                    } else if(todayEntry.getKey().isAfter(prevEntry.getKey()) && todayEntry.getKey().isBefore(currEntry.getKey())) {
                        currEntry.setValue(currEntry.getValue() + todayEntry.getValue());
                    }
                }
            }
        }

Solution

  • It seems easiest to first build a daily map of cumulative sums, then filter out only the mondays:

    public static Map<LocalDate, Integer> cumulativeWeeklySum(SortedMap<LocalDate, Integer> data) {
        AtomicInteger cumulativeSum = new AtomicInteger(0);
        return data.entrySet().stream()
            .collect(Collectors.toMap(Map.Entry::getKey, e -> cumulativeSum.addAndGet(e.getValue())))
            .entrySet().stream()
            .filter(e -> e.getKey().getDayOfWeek() == DayOfWeek.MONDAY || e.getKey().equals(data.lastKey()))
            .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
    }
    

    edit:

    If you want to retain the order of the resulting map, you can modify the last collect() call:

    .collect(Collectors.toMap(
                 Map.Entry::getKey, Map.Entry::getValue,
                 (v1, v2) -> { throw new RuntimeException("Duplicate key - can't happen"); },
                 TreeMap::new));