2015-05-17 18 views
11

Il mio primo tentativo con Java 8 flussi ...java 8 - torrente, la mappa e il conteggio distinto

Ho un oggetto di offerta, che rappresenta un'offerta di un utente per un oggetto in un'asta. ho una lista di offerte e voglio fare una mappa che conta in quante (distinte) aste l'utente ha fatto un'offerta.

questo è il mio prendere su di esso:

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

Funziona, ma mi sento come se sto tradendo, causa riprodurre in streaming i set di ingresso della mappa, invece di fare una manipolazione sul flusso iniziale. .. deve essere un modo più corretto di fare questo, ma non ho potuto capirlo ...

Grazie

+3

Puoi includere la dichiarazione dell'oggetto delle offerte? – Nick

risposta

15

è possibile eseguire groupingBy due volte:

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

In questo modo hai quante offerte ogni utente ha in ogni asta. Quindi la dimensione della mappa interna è il numero di aste che l'utente ha partecipato. Se non avete bisogno di informazioni supplementari, si può fare questo:

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

Questo è esattamente quello che vi serve: la mappatura degli utenti per numero di utenti aste partecipato.

Update: c'è anche una soluzione simile, che è più vicino al tuo esempio: la risposta di

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

Sì, ho cancellato il mio commento da quando ho capito che dovrebbe essere quello che hai appena aggiunto. Stavo postando prima di pensare. – Radiodef

+3

Eccellente! questo è esattamente quello che stavo cercando, il metodo 'collectingAndThen', che non riuscivo a capire come usare. Molte grazie :) – Zemer

0

Tagir Valeev è quella giusta (+1). Eccone un altro che fa esattamente lo stesso usando il tuo Collector downstream per il gruppo:

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)); 
     } 
    })); 
Problemi correlati