Java 8 - поток, карта и счетчик

Моя первая попытка с потоками java 8...

У меня есть объект Bid, который представляет заявку пользователя на предмет на аукционе. У меня есть список ставок, и я хочу сделать карту, которая подсчитывает, сколько (разных) аукционов пользователь сделал ставку.

это мое взятие на себя:

bids.stream()
         .collect(
             Collectors.groupingBy(
                  bid ->  Bid::getBidderUserId, 
                  mapping(Bid::getAuctionId, Collectors.toSet())
             )
         ).entrySet().stream().collect(Collectors.toMap(
             e-> e.getKey(),e -> e.getValue().size())
        );

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

Спасибо

Ответы

Ответ 1

Вы можете выполнить groupingBy дважды:

Map<Integer, Map<Integer, Long>> map = bids.stream().collect(
        groupingBy(Bid::getBidderUserId,
                groupingBy(Bid::getAuctionId, counting())));

Таким образом, у вас есть, сколько ставок каждый пользователь имеет на каждом аукционе. Таким образом, размер внутренней карты - количество аукционов, в которых участвовал пользователь. Если вам не нужна дополнительная информация, вы можете сделать это:

Map<Integer, Integer> map = bids.stream().collect(
        groupingBy(
                Bid::getBidderUserId,
                collectingAndThen(
                        groupingBy(Bid::getAuctionId, counting()),
                        Map::size)));

Это именно то, что вам нужно: сопоставление пользователей с количеством участников аукциона.

Обновление: тоже похожее решение, которое ближе к вашему примеру:

Map<Integer, Integer> map = bids.stream().collect(
        groupingBy(
                Bid::getBidderUserId,
                collectingAndThen(
                        mapping(Bid::getAuctionId, toSet()),
                        Set::size)));

Ответ 2

Ответ Тагира Валеева правильный (+1). Вот еще один, который делает то же самое, используя ваш собственный нисходящий коллектор для groupBy:

    Map<Integer, Long> map = bids.stream().collect(
               Collectors.groupingBy(Bid::getBidderUserId, 
                                     new Collector<Bid, Set<Integer>, Long>() {

        @Override
        public Supplier<Set<Integer>> supplier() {
            return HashSet::new;
        }

        @Override
        public BiConsumer<Set<Integer>, Bid> accumulator() {
            return (s, b) -> s.add(b.getAuctionId());
        }

        @Override
        public BinaryOperator<Set<Integer>> combiner() {
            return (s1, s2) -> {
                s1.addAll(s2);
                return s1;
            };
        }

        @Override
        public Function<Set<Integer>, Long> finisher() {
            return (s) -> Long.valueOf(s.size());
        }

        @Override
        public Set<java.util.stream.Collector.Characteristics> characteristics() {
            return Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.UNORDERED, Collector.Characteristics.IDENTITY_FINISH));
        }
    }));