Java8-流、映射和计数不同

Java8-流、映射和计数不同,java,java-8,java-stream,Java,Java 8,Java Stream,我第一次尝试使用Java8流 我有一个对象出价,它表示用户在拍卖中对某个项目的出价。我有一个出价列表,我想制作一张地图,统计用户出价的(不同的)拍卖次数 这是我对它的看法: bids.stream() .collect( Collectors.groupingBy( bid -> Bid::getBidderUserId, mapping(Bid::getAuctionI

我第一次尝试使用Java8流

我有一个对象出价,它表示用户在拍卖中对某个项目的出价。我有一个出价列表,我想制作一张地图,统计用户出价的(不同的)拍卖次数

这是我对它的看法:

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())
        );
这是可行的,但我觉得我在作弊,因为我流化了地图的条目集,而不是对初始流进行操作。。。这肯定是一个更正确的方法,但我想不出来


谢谢

您可以执行两次分组:

Map<Integer, Map<Integer, Long>> map = bids.stream().collect(
        groupingBy(Bid::getBidderUserId,
                groupingBy(Bid::getAuctionId, counting())));
Map Map=bids.stream().collect(
groupingBy(Bid::getBidderUserId,
分组方式(Bid::getAuctionId,counting());
这样,您就可以知道每个用户在每次拍卖中有多少次出价。因此,内部地图的大小是用户参与拍卖的次数。如果不需要其他信息,可以执行以下操作:

Map<Integer, Integer> map = bids.stream().collect(
        groupingBy(
                Bid::getBidderUserId,
                collectingAndThen(
                        groupingBy(Bid::getAuctionId, counting()),
                        Map::size)));
Map Map=bids.stream().collect(
分组依据(
Bid::getBidderUserId,
收集然后(
groupingBy(Bid::getAuctionId,counting()),
地图:大小),;
这正是您需要的:将用户映射到用户参与的拍卖数量

更新:还有类似的解决方案更接近您的示例:

Map<Integer, Integer> map = bids.stream().collect(
        groupingBy(
                Bid::getBidderUserId,
                collectingAndThen(
                        mapping(Bid::getAuctionId, toSet()),
                        Set::size)));
Map Map=bids.stream().collect(
分组依据(
Bid::getBidderUserId,
收集然后(
映射(Bid::getAuctionId,toSet()),
Set::size));

Tagir Valeev的答案是正确的(+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));
        }
    }));
Map Map=bids.stream().collect(
Collectors.groupingBy(Bid::getBidderUserId,
新收集器(){
@凌驾
公共供应商(){
返回HashSet::new;
}
@凌驾
公共双消费者累加器(){
返回(s,b)->s.add(b.getAuctionId());
}
@凌驾
公共二进制运算符组合器(){
返回(s1、s2)->{
s1.addAll(s2);
返回s1;
};
}
@凌驾
公共函数完成器(){
return(s)->Long.valueOf(s.size());
}
@凌驾
公共集特征(){
返回Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.UNORDERED,Collector.Characteristics.IDENTITY_FINISH));
}
}));

您能将您的投标对象声明包括在内吗?是的,我删除了我的评论,因为我意识到它应该是您刚才添加的内容。我在想之前就发帖了。太棒了!这正是我想要的,
收集然后
方法,我不知道如何使用它。非常感谢:)