validate - java stream distinct object
java 8-stream, map y count distinct (2)
Mi primer intento con java 8 streams ...
Tengo un objeto Oferta, que representa una oferta de un usuario por un artículo en una subasta. tengo una lista de ofertas, y quiero hacer un mapa que cuente en cuántas subastas (distintas) el usuario hizo una oferta.
Esta es mi opinión sobre ella:
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())
);
Funciona, pero siento que estoy haciendo trampa, porque transmito los juegos de entrada del mapa, en lugar de hacer una manipulación en la transmisión inicial ... debe ser una forma más correcta de hacerlo, pero no podía entender fuera...
Gracias
La respuesta de Tagir Valeev es la correcta (+1). Aquí hay uno adicional que hace exactamente lo mismo usando tu propio recopilador aguas abajo para el grupo Por:
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));
}
}));
Puede realizar groupingBy
dos veces:
Map<Integer, Map<Integer, Long>> map = bids.stream().collect(
groupingBy(Bid::getBidderUserId,
groupingBy(Bid::getAuctionId, counting())));
De esta forma, tiene cuántas ofertas tiene cada usuario en cada subasta. Entonces, el tamaño del mapa interno es el número de subastas en las que participó el usuario. Si no necesita la información adicional, puede hacer esto:
Map<Integer, Integer> map = bids.stream().collect(
groupingBy(
Bid::getBidderUserId,
collectingAndThen(
groupingBy(Bid::getAuctionId, counting()),
Map::size)));
Esto es exactamente lo que necesita: asignación de usuarios a la cantidad de usuarios de subastas que participó.
Actualización: también hay una solución similar que está más cerca de su ejemplo:
Map<Integer, Integer> map = bids.stream().collect(
groupingBy(
Bid::getBidderUserId,
collectingAndThen(
mapping(Bid::getAuctionId, toSet()),
Set::size)));