2015-05-17 18 views
11

moja pierwsza próba z Java 8 strumieni ...java 8 - Strumień, mapę i policzyć odrębną

mam obiektu oferty, co stanowi stawkę użytkownika dla elementu w aukcji. Mam listę ofert i chcę utworzyć mapę liczącą na ile (odrębnych) aukcji użytkownik złożył ofertę.

to jest moje zdanie na jej temat:

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

To działa, ale czuję się jakbym oszukiwał, bo I Stream zestawy wjazdowych mapie, zamiast robić manipulacji na początkowym strumienia. .. musi być bardziej poprawny sposób to zrobić, ale nie mogłem zrozumieć to ...

Dzięki

+3

Czy możesz podać swoją deklarację przedmiotu oferty? – Nick

Odpowiedz

15

groupingBy można wykonać dwukrotnie:

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

W ten sposób masz liczbę ofert każdego użytkownika w każdej aukcji. Rozmiar mapy wewnętrznej to liczba aukcji, w których uczestniczył użytkownik. Jeśli nie potrzebujesz dodatkowych informacji, możesz to zrobić:

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

Dokładnie tego potrzebujesz: mapowanie użytkowników do liczby aukcji, w których uczestniczył użytkownik.

Aktualizacja: istnieje podobne rozwiązanie, które jest bliżej przykład: odpowiedź

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

Tak, usunąłem swój komentarz, ponieważ zdałem sobie sprawę, że powinno to być to, co właśnie dodałeś. Pisałem przed myśleniem. – Radiodef

+3

Doskonale! właśnie tego szukałem, metody "collectAndThen", której nie mogłem wymyślić. Wielkie dzięki :) – Zemer

0

Tagir Valeev jest słuszna (+1). Oto dodatkowy, który robi dokładnie to samo, używając własnego kolektora końcowego dla grupy:

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)); 
     } 
    })); 
Powiązane problemy