Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

java 8 - stream, map and count distinct

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 map that counts in how many (distinct) auctions the user made a bid.

this is my take on it:

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())
        );

It works, but i feel like i'm cheating, cause i stream the entry sets of the map, instead of doing a manipulation on the initial stream... must be a more correct way of doing this, but i couldn't figure it out...

Thanks

like image 665
Zemer Avatar asked May 17 '15 02:05

Zemer


1 Answers

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)));
like image 56
Tagir Valeev Avatar answered Oct 20 '22 00:10

Tagir Valeev