values validate property collection java java-8 java-stream

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