HashMap.merge() через Stream API

202
02 августа 2021, 17:00

Есть метод, в котором алгоритм прописан через обычную итерацию по List:

public static List<UserMealWithExceed> getFilteredWithExceeded(List<UserMeal> mealList, LocalTime startTime, LocalTime endTime, int caloriesPerDay) {
        Map<LocalDate, Integer> caloriesOfDayMap = new HashMap<>();
        List<UserMealWithExceed> userList = new ArrayList<>();
        LocalDate date;
        LocalTime time;
        for (UserMeal um : mealList) {
            date = TimeUtil.toLocalDate(um.getDateTime());
            Integer calories = um.getCalories();
            caloriesOfDayMap.merge(date, calories, Integer::sum);
        }
        for (UserMeal um : mealList) {
            time = TimeUtil.toLocalTime(um.getDateTime());
            if (TimeUtil.isBetween(time, startTime, endTime)) {
                date = TimeUtil.toLocalDate(um.getDateTime());
                int caloriesOfDate = caloriesOfDayMap.get(date);
                boolean isExceeds = caloriesOfDate >= caloriesPerDay;
                userList.add(new UserMealWithExceed(um.getDateTime(), um.getDescription(), um.getCalories(), isExceeds));
            }
        }
        return userList;
    }

Задача - реализовать алгоритм через Stream API. Проблема - не могу сообразить, как использовать stream().collect именно для выполнения функции merge(). Прошу помощи

Answer 1
public static List<UserMealWithExceed> getFilteredWithExceeded(List<UserMeal> mealList,
        LocalTime startTime, LocalTime endTime, int caloriesPerDay) {
    final Map<LocalDate, Integer> caloriesOfDayMap = 
            mealList.stream().collect(Collectors.toMap(um->um.getDateTime().toLocalDate(), um->um.getCalories(), Integer::sum));
    return mealList.stream()
            .filter(um -> um.getDateTime().toLocalTime().isAfter(startTime)
                    && um.getDateTime().toLocalTime().isBefore(endTime))
            .map(um->createUserMealWithExceed(caloriesOfDayMap, um, caloriesPerDay))
            .collect(Collectors.toList());
}
private static UserMealWithExceed createUserMealWithExceed(Map<LocalDate, Integer> caloriesOfDayMap, UserMeal um, int caloriesPerDay){
    boolean isExceeds = caloriesOfDayMap.get(um.getDateTime().toLocalDate()) >= caloriesPerDay;
    return new UserMealWithExceed(um.getDateTime(), um.getDescription(), um.getCalories(), isExceeds);
}

Полагаю, что в классе UserMeal dateTime имеет тип LocalDateTime (иначе это странно). В этом случае никаких дополнительных утилит в виде TimeUtil не требуется, все уже есть из коробки в пакете java.time.

Answer 2
public static List<UserMealWithExceed> getFilteredWithExceeded(List<UserMeal> mealList, 
                                                               LocalTime startTime, 
                                                               LocalTime endTime, 
                                                               int caloriesPerDay) {
    Map<LocalDate, Integer> caloriesOfDayMap = mealList.stream()
            .collect(Collectors.groupingBy(um -> TimeUtil.toLocalDate(um.getDateTime()), 
                    Collectors.summingInt(UserMeal::getCalories)));
    return mealList.stream()
            .filter(um -> TimeUtil.isBetween(TimeUtil.toLocalTime(um.getDateTime()), 
                                             startTime, 
                                             endTime))
            .map(um -> new UserMealWithExceed(um.getDateTime(), 
                                              um.getDescription(), 
                                              um.getCalories(), 
                                              caloriesOfDayMap.get(TimeUtil.toLocalDate(um.getDateTime()) >= caloriesPerDay))
            .collect(Collectors.toList());
}

Разумеется, можно насоздавать для каждой операции нужные функциональные объекты и запихнуть громоздкий код в них, будет красивее выглядеть.

READ ALSO
Как получить одно из двух значений Object из Map&lt;String, Object&gt; и поместить его в List&lt;&gt;?

Как получить одно из двух значений Object из Map<String, Object> и поместить его в List<>?

От сервера с помощью Retrofit я получаю данные в виде:

223
Exception in thread &ldquo;main&rdquo; java.util.InputMismatchException at java.util.Scanner.throwFor(Unknown Source)

Exception in thread “main” java.util.InputMismatchException at java.util.Scanner.throwFor(Unknown Source)

Задача: На числовой прямой дан отрезок [3;8]Требуется определить, принадлежит ли точка x данному отрезку

223
Websocket выдает ERR_SSL_PROTOCOL_ERROR

Websocket выдает ERR_SSL_PROTOCOL_ERROR

Пытаясь подключится к localhost:3000 выдает ошибку (в названии), я пробовал подключать вебсокет по адресу "localhost:3000", "localhost", "3000", все кроме localhost выдает...

176