Группировка списка по условию в зависимости от другого списка

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

public class Main {

    public static void main(String[] args) {

        LocalDate n = LocalDate.from(LocalDate.now());

        List<LocalDate> groupingDates = Arrays.asList(n, n.plusDays(10), n.plusDays(20));
        List<Item> itemsToBeGrouped = Arrays.asList(
                //should go to group labeled by "n"
                new Item(n, n.plusDays(1)),
                new Item(n.minusDays(5), n.plusDays(7)),

                //should go to group labeled by "n.plusDays(10)"
                new Item(n.plusDays(5), n.plusDays(11)),

                //should go to group labeled by "n.plusDays(20)"
                new Item(n.plusDays(15), n.plusDays(20)));

        Map<LocalDate, List<Item>> groupedItems = new LinkedHashMap<>();
        for(Item i : itemsToBeGrouped) {
            for (LocalDate date : groupingDates) {
                if (isActiveOnDate(i, date)) {
                    if (!groupedItems.containsKey(date)) {
                        groupedItems.put(date, new ArrayList<>());
                    }
                    groupedItems.get(date).add(i);
                }
            }
        }

        System.out.println(groupedItems);
    }

    static boolean isActiveOnDate(Item item, LocalDate date) {
        return !item.start.isAfter(date) && !item.end.isBefore(date);
    }
}

public class Item{
    public LocalDate start;
    public LocalDate end;

    public Item(LocalDate start, LocalDate end) {
        this.start = start;
        this.end = end;
    }

    @Override
    public String toString() {
        return "Item{" +
                "start = " + start +
                ", end = " + end +
                '}';
    }
}

Где твои проблемы? Вы можете просто использовать Collectors.groupingBy с подходящим ключом (что означает передачу функции, которая выполняет итерацию по этим датам, как это делаете вы ...)

Giacomo Alzetta 10.08.2018 14:12
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
1
72
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Сделайте то же самое в лямбде groupingBy, как и в for-loop, выберите первую дату, которой соответствует элемент, а затем используйте ее в качестве ключа:

Map<LocalDate, List<Item>> groupedItems = itemsToBeGrouped.stream()
    .collect(Collectors.groupingBy(i -> groupingDates.stream()
        .filter(d -> isActiveOnDate(i, d))
        .findFirst() // Optional<Date>
        .get() // will throw if nothing matches
    ));

Я рекомендую findFirst() вместо findAny().

Nikolas Charalambidis 10.08.2018 14:26

Что вы имеете в виду под «несогласованными данными»? любой пример?

Nikolas Charalambidis 10.08.2018 14:28

@Nikolas nevermind, я прочитал что-то в коде OP, которого даже нет. findFirst следует предпочесть для единообразия. Так что вы совершенно правы, я редактировал :)

Lino 10.08.2018 14:31
 Map<LocalDate, List<Item>> groupedItems2 = itemsToBeGrouped.stream()
            .flatMap(x -> groupingDates.stream()
                    .filter(y -> isActiveOnDate(x, y))
                    .map(y -> new SimpleEntry<>(x, y)))
            .collect(Collectors.groupingBy(
                    SimpleEntry::getValue,
                    LinkedHashMap::new,
                    Collectors.mapping(Entry::getKey, Collectors.toList())));

Другие вопросы по теме