java 8 - stream, map and count distinct

前端 未结 2 1967
你的背包
你的背包 2020-12-03 14:24

My first attempt with java 8 streams...

I have an object Bid, which represents a bid of a user for an item in an auction. i have a list of bids, and i want to make a

相关标签:
2条回答
  • 2020-12-03 14:28

    Tagir Valeev's answer is the right one (+1). Here is an additional one that does exactly the same using your own downstream Collector for the 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));
            }
        }));
    
    0 讨论(0)
  • 2020-12-03 14:38

    You can perform groupingBy twice:

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

    This way you have how many bids each user has in each auction. So the size of internal map is the number of auctions the user participated. If you don't need the additional information, you can do this:

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

    This is exactly what you need: mapping of users to number of auctions user participated.

    Update: there's also similar solution which is closer to your example:

    Map<Integer, Integer> map = bids.stream().collect(
            groupingBy(
                    Bid::getBidderUserId,
                    collectingAndThen(
                            mapping(Bid::getAuctionId, toSet()),
                            Set::size)));
    
    0 讨论(0)
提交回复
热议问题