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

它工作,但我觉得我在作弊,因为我流式传输地图的入口集,而不是在初始流上做一个操作…必须是一个更正确的方式这样做,但我无法想象出来…

谢谢

您可以执行两次groupingBy

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

这样,每个用户在每次竞价中都会有多少出价。 因此内部地图的大小是用户参与的拍卖数量。 如果您不需要其他信息,可以执行以下操作:

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

这正是您所需要的:将用户映射到用户参与的拍卖数量。

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

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

Tagir Valeev的答案是正确的(+1)。 这是另一个使用您自己的groupBy下游收集器完全相同的:

  Map map = bids.stream().collect( Collectors.groupingBy(Bid::getBidderUserId, new Collector, Long>() { @Override public Supplier> supplier() { return HashSet::new; } @Override public BiConsumer, Bid> accumulator() { return (s, b) -> s.add(b.getAuctionId()); } @Override public BinaryOperator> combiner() { return (s1, s2) -> { s1.addAll(s2); return s1; }; } @Override public Function, Long> finisher() { return (s) -> Long.valueOf(s.size()); } @Override public Set characteristics() { return Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.UNORDERED, Collector.Characteristics.IDENTITY_FINISH)); } }));