java 8 - 不同的流、映射和计数
java 8 - stream, map and count distinct
我第一次尝试 java 8 个流...
我有一个对象出价,它表示用户对拍卖中的物品的出价。我有一个出价列表,我想制作一张地图来计算用户出价的次数(不同的)。
这是我的看法:
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<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)));
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));
}
}));
我第一次尝试 java 8 个流...
我有一个对象出价,它表示用户对拍卖中的物品的出价。我有一个出价列表,我想制作一张地图来计算用户出价的次数(不同的)。
这是我的看法:
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<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)));
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));
}
}));