2015-09-20 22 views
8

Edit :: Jestem Parafrazując pytanie więc, że jest to bardziej oczywisteJava 8 Streams - Grupowanie strumień krotki

Pisałem ten kod

List<ImmutablePair<Integer, Integer>> list = new ArrayList<ImmutablePair<Integer, Integer>>(); 
    list.add(new ImmutablePair(1, 1)); 
    list.add(new ImmutablePair(1, 1)); 
    list.add(new ImmutablePair(1, 1)); 
    list.add(new ImmutablePair(2, 2)); 
    list.add(new ImmutablePair(2, 2)); 
    list.add(new ImmutablePair(2, 2)); 
    list.add(new ImmutablePair(3, 3)); 
    list.add(new ImmutablePair(3, 3)); 
    list.add(new ImmutablePair(3, 3)); 
    Stream<ImmutablePair<Integer, Integer>> stream = list.stream(); 
    Map<Integer, Integer> result = stream.collect(Collectors.groupingBy(
     ImmutablePair::getLeft, 
      Collectors.mapping(
        ImmutablePair::getRight, 
        Collectors.summingInt(Comparator.comparing(ImmutablePair::getRight)) 
      )     
    )); 

Chcę przetworzyć tę listę za pomocą paruje tak że wyjście jest mapą zawierającą klucze (1, 3), (2, 6), (3, 9)

Tak więc, po prostu grupujemy lewą pozycję krotki, a następnie sumujemy właściwą pozycję.

Ten kod nie jest kompilowany, a kompilator mówi, że nie może rozwiązać metod getLeft, getRight.

Oto komunikaty o błędach z kompilatora

/Users/abhi/JavaProjects/MovieLambda2/src/main/java/com/abhi/MovieLambda2.java:229: error: method summingInt in class Collectors cannot be applied to given types; 
          Collectors.summingInt(Comparator.comparing(ImmutablePair::getRight)) 
            ^
    required: ToIntFunction<? super T#1> 
    found: Comparator<Object> 
    reason: no instance(s) of type variable(s) T#2,U exist so that Comparator<T#2> conforms to ToIntFunction<? super T#1> 
    where T#1,T#2,U are type-variables: 
    T#1 extends Object declared in method <T#1>summingInt(ToIntFunction<? super T#1>) 
    T#2 extends Object declared in method <T#2,U>comparing(Function<? super T#2,? extends U>) 
    U extends Comparable<? super U> declared in method <T#2,U>comparing(Function<? super T#2,? extends U>) 
/Users/abhi/JavaProjects/MovieLambda2/src/main/java/com/abhi/MovieLambda2.java:229: error: incompatible types: cannot infer type-variable(s) T,U 
          Collectors.summingInt(Comparator.comparing(ImmutablePair::getRight)) 
                    ^
    (argument mismatch; invalid method reference 
     no suitable method found for getRight(Object) 
      method Pair.getRight() is not applicable 
      (actual and formal argument lists differ in length) 
      method ImmutablePair.getRight() is not applicable 
      (actual and formal argument lists differ in length)) 
    where T,U are type-variables: 
    T extends Object declared in method <T,U>comparing(Function<? super T,? extends U>) 
    U extends Comparable<? super U> declared in method <T,U>comparing(Function<? super T,? extends U>) 
/Users/abhi/JavaProjects/MovieLambda2/src/main/java/com/abhi/MovieLambda2.java:229: error: invalid method reference 
          Collectors.summingInt(Comparator.comparing(ImmutablePair::getRight)) 
                    ^
    non-static method getRight() cannot be referenced from a static context 
    where R is a type-variable: 
    R extends Object declared in class ImmutablePair 
/Users/abhi/JavaProjects/MovieLambda2/src/main/java/com/abhi/MovieLambda2.java:228: error: invalid method reference 
          ImmutablePair::getRight, 
          ^
    non-static method getRight() cannot be referenced from a static context 
    where R is a type-variable: 
    R extends Object declared in class ImmutablePair 
/Users/abhi/JavaProjects/MovieLambda2/src/main/java/com/abhi/MovieLambda2.java:226: error: invalid method reference 
        ImmutablePair::getLeft, 
        ^
    non-static method getLeft() cannot be referenced from a static context 
    where L is a type-variable: 
    L extends Object declared in class ImmutablePair 
+3

Powinieneś zamieścić prosty przykład demonstrujący problem, w przeciwnym razie trudno nam go odtworzyć. – Tunaki

+1

Co z kolorem Collectors.groupBy (ImmutablePair :: getLeft)? Mam na myśli osobno. Czy to także się nie udaje? –

+2

Próbujesz grupować instancje ImmutablePair, odwołując się do metody Movie. To nie może działać. To jak sortowanie osób według koloru banana. Możesz sortować ludzi według ich wzrostu, wagi lub wieku, ale nie przez własność banana. Możemy wyjaśnić, co dokładnie oznacza komunikat o błędzie, jeśli wysłałeś dokładny komunikat o błędzie zamiast parafrazować go i podajesz własne, błędne zrozumienie wiadomości. Możemy pomóc Ci naprawić kod, jeśli opublikujesz zaangażowane zajęcia. –

Odpowiedz

4

Aktualizacja: ten odpowiada na pierwotne pytanie (revision 2). Nowe pytanie jest dobrze odpowiedzi @ Shiraaz.M.


Twój Comparator akceptuje parę, więc trzeba zadzwonić getRight z Collectors.mapping:

Map<String, Optional<Movie>> map = ml.getDataAsStream() 
    .<ImmutablePair<String, Movie>>flatMap(x -> x.getGenre() 
      .map(g -> new ImmutablePair<String, Movie>(g, x))) 
    .collect(
      Collectors.groupingBy(
       ImmutablePair::getLeft, 
       Collectors.mapping(ImmutablePair::getRight, 
        Collectors.maxBy(Comparator.comparing(Movie::getVoteCount))) 
      )); 

Należy pamiętać, że w zależności od używanego kompilatora może trzeba określić kilka rodzajów wyraźnie jak automatyczne wnioskowanie może zakończyć się niepowodzeniem.

W rzeczywistości takie scenariusze są dobrze obsługiwane w mojej bibliotece StreamEx, która poprawia standardowe strumienie Java. Ten sam efekt można uzyskać pisząc w ten sposób:

Map<String, Optional<Movie>> map = StreamEx.of(ml.getDataAsStream()) 
    .cross(Movie::getGenre) // create (Movie, Genre) entries 
    .invert() // swap entries to get (Genre, Movie) 
    .grouping(Collectors.maxBy(Comparator.comparing(Movie::getVoteCount))); 

wreszcie zauważyć, że za pomocą maxBy kolektor musisz Optional wartości, które są bezużyteczne, ponieważ nie może być pusta.Dla maxBy/minBy scenariuszy lepiej wykorzystywać toMap kolektor z funkcją zwyczaj scalenia:

Map<String, Movie> map = ml.getDataAsStream() 
    .<ImmutablePair<String, Movie>>flatMap(x -> x.getGenre() 
      .map(g -> new ImmutablePair<String, Movie>(g, x))) 
    .collect(Collectors.toMap(ImmutablePair::getLeft, ImmutablePair::getRight, 
      BinaryOperator.maxBy(Comparator.comparing(Movie::getVoteCount)))); 

lub używając StreamEx:

Map<String, Movie> map = StreamEx.of(ml.getDataAsStream()) 
    .cross(Movie::getGenre) 
    .invert() 
    .toMap(BinaryOperator.maxBy(Comparator.comparing(Movie::getVoteCount))); 
+0

Myślę, że mój poprzedni przykład był trochę skomplikowany. więc I –

+0

To nie zadziałało. Zaimplementowałem powyższą sugestię. ale nadal dostaję komunikat kompilatora 'nie można rozwiązać getLeft' –

+2

Ciekawe, co robi funkcja invert()? –

6

Zakładając klasa ImmutablePair wygląda następująco (klasa ta może trzeba być statyczna w zależności od tego, czy przykładowy kod został wykonany ze obrębie głównej metody):

class ImmutablePair<T,T2> { 
    private final T left; 
    private final T2 right; 

    public ImmutablePair(T left, T2 right) { 
     this.left = left; 
     this.right = right; 

    } 

    public T getLeft() { 
     return left; 
    } 

    public T2 getRight() { 
     return right; 
    } 
} 

To wydaje się działać dla mnie:

List<ImmutablePair<Integer, Integer>> list = new ArrayList<>(); 
    list.add(new ImmutablePair(1, 1)); 
    list.add(new ImmutablePair(1, 1)); 
    list.add(new ImmutablePair(1, 1)); 
    list.add(new ImmutablePair(2, 2)); 
    list.add(new ImmutablePair(2, 2)); 
    list.add(new ImmutablePair(2, 2)); 
    list.add(new ImmutablePair(3, 3)); 
    list.add(new ImmutablePair(3, 3)); 
    list.add(new ImmutablePair(3, 3)); 
    Map<Integer, Integer> collect = list.stream() 
     .collect(
      Collectors.groupingBy(
       ImmutablePair::getLeft, 
       Collectors.summingInt(ImmutablePair::getRight))); 

    System.out.println(collect); 

, a wynik:

{1 = 3, 2 = 6, 3 = 9}

Możliwe problemem

Problemem jest ta sekcja kodu:

 Collectors.mapping(
       ImmutablePair::getRight, 
       Collectors.summingInt(Comparator.comparing(ImmutablePair::getRight)) 
     ) 

Collectors.mapping kolektor pierwszy dostosowuje obiekt typu T do i obiekt typu U, a następnie biegnie kolektor typu U. (That's the gist of the javadoc for me)

Więc co robisz, jest coś takiego:

  • Przekształć ImmutablePair w liczbę całkowitą.
  • Drugi parametr to teraz Collector, który oczekuje typu Integer, ale "używasz typu ImmutablePair". Dodatkowo, Comparator.compare() zwraca Komparator i szukasz zwracającego typu Integer. Tak aby ustalić dokładną linię kodu, aby zmienić go na coś takiego:

Collectors.mapping (ImmutablePair :: GetRight, Collectors.summingInt (Integer :: valueOf))

Ale nie trzeba tego powodu można uprościć ten wywołując Collectors.summingInt bezpośrednio:

Collectors.summingInt (ImmutablePair :: GetRight)

Powiązane problemy