Stream Java – поиск максимального значения свойства для каждой группы объектов

Есть list объектов:

SuvLogDto{
private String system;
private Date dateTime;
private String x;
...
}

Из этого листа нужно выбрать элементы у которых dateTime будет максимальной в его группе, образованной по свойству system.

По сути нужно сделать группировку по system, а потом внутри образовавшихся групп выбрать максимальный по dateTime элемент.

Как пытаюсь это сделать:

Map<String, SuvLogDto> mostExpensives = suvLogDtos.stream().collect(Collectors.toMap(SuvLogDto::getSystem, Function.identity()),
                    BinaryOperator.maxBy(Comparator.comparing(SuvLogDto::getDateTime)));

Это должно подойти, потому что:

<T,K,U> Collector<T,?,Map<K,U>> toMap(
                                  Function<? super T,? extends K> keyMapper,
                                  Function<? super T,? extends U> valueMapper,
                                  BinaryOperator<U> mergeFunction)

keyMapper: функция сопоставления для создания ключей сопоставления для каждого элемента входного потока. valueMapper: функция сопоставления для создания значений сопоставления для каждого элемента входного потока. mergeFunction: бинарный оператор, предназначенный для разрешения коллизий между значениями, связанными с одним и тем же ключом. Входными данными для этой функции являются значения, принадлежащие одному и тому же ключу.

Но Java мне выдает ошибку:

Cannot resolve method 'collect(java.util.stream.Collector<T,capture<?>,java.util.Map<K,U>>, java.util.function.BinaryOperator)'

Что не так в алгоритме? Как можно поправить?


Ответы (1 шт):

Автор решения: Nowhere Man

У вас в коде небольшая опечатка, так как скобка закрыта до того как был указан третий аргумент в коллекторе toMap, должно быть так:

List<SuvLogDto> suvLogDtos = Arrays.asList(
    new SuvLogDto("sys1", new Date(System.currentTimeMillis() - 1000), "1 - 1000"),
    new SuvLogDto("abc", new Date(System.currentTimeMillis() - 2000), "abc-2000"),
    new SuvLogDto("sys1", new Date(System.currentTimeMillis() - 2000), "1 - 2000"),
    new SuvLogDto("xyz", new Date(System.currentTimeMillis() - 3000), "xyz - 3K"),
    new SuvLogDto("abc", new Date(System.currentTimeMillis() - 500), "abc - 500")
);

Map<String, SuvLogDto> mostExpensives = suvLogDtos
    .stream()
    .collect(Collectors.toMap(
        SuvLogDto::getSystem, 
        Function.identity(),
        BinaryOperator.maxBy(Comparator.comparing(SuvLogDto::getDateTime))
    ));

mostExpensives.forEach((k, v) -> System.out.println(k + ": " + v));

Вывод результата:

sys1: SuvLogDto[system=sys1, date=Fri Sep 16 17:08:53 GMT 2022, x=1 - 1000]
abc: SuvLogDto[system=abc, date=Fri Sep 16 17:08:53 GMT 2022, x=abc - 500]
xyz: SuvLogDto[system=xyz, date=Fri Sep 16 17:08:51 GMT 2022, x=xyz - 3K]

Также можно дополнительно указать LinkedHashMap::new в качестве четвертого аргумента, чтобы получить мапу, поддерживающую порядок вставки (если нужно).

→ Ссылка