簡體   English   中英

Java 8 Streams - 對元組流進行分組

[英]Java 8 Streams - Grouping a stream of tuples

編輯::我正在改寫這個問題,以便更清楚

我寫了這段代碼

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

我想使用steams處理此列表,以便輸出是包含鍵(1,3),(2,6),(3,9)的映射

所以基本上,我們將元組的左側項目分組,然后對正確的項目求和。

這段代碼沒有編譯,編譯器說它無法解析getLeft,getRight方法。

以下是編譯器的錯誤消息

/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

假設你的ImmutablePair類看起來像這樣(這個類可能需要是靜態的,這取決於示例代碼是否是在main方法中執行的):

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

這似乎對我有用:

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

結果是:

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

可能的問題

問題出在這部分代碼中:

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

Collectors.mapping收集器首先將類型為T的對象調整為U類型的對象,然后在類型U上運行收集器。( 這是我的javadoc的要點

所以你正在做的是:

  • 將ImmutablePair轉換為整數。
  • 第二個參數現在是一個期望Integer類型的收集器,但您正在“使用ImmutablePair類型”。 此外,Comparator.compare()返回一個Comparator,您希望返回一個Integer類型。 因此,修復您確切的代碼行是將其更改為:

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

但是你不需要這個,因為你可以通過直接調用Collectors.summingInt來簡化這個:

Collectors.summingInt(ImmutablePair :: GetRight時)

更新:這回答了一個原始問題( 修訂版2 )。 @ Shiraaz.M很好地回答了新問題。


您的Comparator接受一對,因此您需要使用Collectors.mapping調用getRight

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

請注意,根據所使用的編譯器,您可能需要明確指定某些類型,因為自動推斷可能會失敗。

實際上,我的StreamEx庫中很好地支持這種場景,它增強了標准的Java Streams。 寫這個可以達到同樣的結果:

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

最后請注意,使用maxBy收集器,您將擁有Optional值,這些值無用,因為它們不能為空。 對於maxBy/minBy場景,最好使用帶有自定義合並功能的toMap collector:

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

或者使用StreamEx:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM