Как получить два списка при помощи Stream API?

А именно. Имеется список неких объектов Cat:

public class Cat {
     LocalDate birthDay;
     int weight;
}

При помощи Stream API я хочу разбить их на две категории по следующему параметру: берём условного cat1 из списка. Если вес всех котов, которые родились в то же время, что и наш кот, больше 100, добавляем его в карту под ключом false, а если меньше или ровно, то в карту под ключом true.

На выходе должна получиться карта Map<Boolean, List<Cat>>. Для таких вещей в Stream API существует метод partitioningBy(), но с ним я могу разделять котов только относительно того, удовлетворяет ли их собственный вес условию, а мне надо, чтобы коты разделялись относительно того, удовлетворяет ли сумма веса всех котов, которые родились с рассматриваемым котом, определённому условию.

Объясните, как такое можно сделать:

  1. Не используя сторонние коллекции.
  2. Не меняя класс.
  3. Желательно, без собственной реализации Collector.

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

Автор решения: Alexandr

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

package com.somepackage;

import lombok.Builder;
import lombok.Data;

import java.time.LocalDate;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Stream;

import static java.util.stream.Collectors.*;

class Main {

    @Data
    @Builder
    public static class Cat {
        LocalDate birthDay;
        int weight;
    }

    public static void main(String[] args) {
        Set<Cat> cats =
                Stream.of(
                        Cat.builder()
                                .birthDay(LocalDate.now().minusDays(1))
                                .weight(100)
                                .build(),
                        Cat.builder()
                                .birthDay(LocalDate.now().minusDays(1))
                                .weight(200)
                                .build(),
                        Cat.builder()
                                .birthDay(LocalDate.now())
                                .weight(50)
                                .build()
                ).collect(toSet());
        Map<LocalDate, Integer> weightByDate =
                cats.stream()
                        .collect(groupingBy(Cat::getBirthDay, summingInt(Cat::getWeight)));
        Map<Boolean, List<Cat>> catsByCondition =
                cats.stream()
                        .collect(partitioningBy(c -> weightByDate.get(c.getBirthDay()) < 100));
        System.out.println(catsByCondition);
    }

}

Результат:

{false=[Main.Cat(birthDay=2020-09-16, weight=100), Main.Cat(birthDay=2020-09-16, weight=200)], true=[Main.Cat(birthDay=2020-09-17, weight=50)]}
→ Ссылка
Автор решения: Alexey R.

Можно сделать так:

Map<Boolean, List<Cat>> sortedCats = cats.stream().collect(Collectors.groupingBy(
        cat -> cats
                .stream()
                .filter(cat1 -> cat1.birthDay.equals(cat.birthDay))
                .collect(Collectors.summingInt(o -> o.weight))
                .intValue() > 100
));
→ Ссылка