2015-05-17 9 views
11

Meinen ersten Versuch mit Java 8 Strömen zählt ...Java 8 - Strom, Karte und verschiedenen

Ich habe ein Objekt Bid, die für ein Element in einer Auktion ein Gebot eines Benutzers darstellt. Ich habe eine Liste von Geboten, und ich möchte eine Karte erstellen, die zählt, in wie vielen (verschiedenen) Auktionen der Benutzer ein Gebot abgegeben hat.

dies ist mein nehmen auf sie:

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

Es funktioniert, aber ich fühle mich wie ich bin zu betrügen, weil ich die Eingabesätze der Karte streamen, stattdessen eine Manipulation an dem anfänglichen Strom zu tun. .. muß ein richtiger Weg, dies zu tun, aber ich kann es nicht herausgefunden ...

Dank

+3

können Sie Ihre Erklärung der Gebote Objekt hinzufügen? – Nick

Antwort

15

können Sie groupingBy zweimal ausführen:

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

Auf diese Weise haben Sie, wie viele Gebote jeder Benutzer in jeder Auktion hat. Die Größe der internen Karte ist also die Anzahl der Auktionen, an denen der Benutzer teilgenommen hat. Wenn Sie nicht über die zusätzliche Informationen benötigen, können Sie dies tun:

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

Das ist genau das, was Sie brauchen: Zuordnung von Benutzern zu Anzahl der Auktionen Nutzer teilgenommen.

Update: gibt es auch ähnliche Lösung, die näher an Ihrem Beispiel ist:

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

Ja, ich habe meinen Kommentar gelöscht, da ich festgestellt habe, dass es das ist, was du gerade hinzugefügt hast. Ich postete, bevor ich nachdachte. – Radiodef

+3

Ausgezeichnet! Das ist genau das, wonach ich gesucht habe, die "CollectingAndThen" -Methode, die ich nicht benutzen konnte. Danke vielmals :) – Zemer

0

Tagir Valeev Antwort ist die richtige (+1). Hier ist eine zusätzliche, die genau das gleiche mit Ihrem eigenen nachgelagerten Collector für die 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)); 
     } 
    }));