2015-07-13 33 views
8

現在,我只能實現兩個集合的笛卡爾乘積,這裏是代碼:被Java 8實現的集合笛卡兒積

public static <T1, T2, R extends Collection<Pair<T1, T2>>> 
R getCartesianProduct(
     Collection<T1> c1, Collection<T2> c2, 
     Collector<Pair<T1, T2>, ?, R> collector) { 
    return c1.stream() 
      .flatMap(e1 -> c2.stream().map(e2 -> new Pair<>(e1, e2))) 
      .collect(collector); 
} 

此代碼工作正常的IntelliJ,但不是在Eclipse中(均爲1.8編譯器遵從性級別):

The method collect(Collector<? super Object,A,R>) 
in the type Stream<Object> is not applicable for 
the arguments (Collector<Pair<T1,T2>,capture#5-of ?,R>) 

這裏是Pair.java:

public class Pair<T1, T2> implements Serializable { 
    protected T1 first; 
    protected T2 second; 
    private static final long serialVersionUID = 1360822168806852921L; 

    public Pair(T1 first, T2 second) { 
     this.first = first; 
     this.second = second; 
    } 

    public Pair(Pair<T1, T2> pair) { 
     this(pair.getFirst(), pair.getSecond()); 
    } 

    public T1 getFirst() { 
     return this.first; 
    } 

    public T2 getSecond() { 
     return this.second; 
    } 

    public void setFirst(T1 o) { 
     this.first = o; 
    } 

    public void setSecond(T2 o) { 
     this.second = o; 
    } 

    public String toString() { 
     return "(" + this.first + ", " + this.second + ")"; 
    } 

    @Override 
    public boolean equals(Object o) { 
     if(!(o instanceof Pair)) 
      return false; 
     Pair p = (Pair) o; 
     if(!this.first.equals(p.first)) 
      return false; 
     if(!this.second.equals(p.second)) 
      return false; 
     return true; 

    } 

    @Override 
    public int hashCode() { 
     int hash = 1; 
     hash = hash * 31 + this.first.hashCode(); 
     hash = hash * 31 + this.second.hashCode(); 
     return hash; 
    } 

} 

如何解決此錯誤?

有沒有一種優雅的方式來實現幾個集合的笛卡爾積? (假設我們有類tuple

+0

Whats'Pair'?你可以爲此提供進口嗎? – Shahzeb

回答

8

Eclipse有類型推斷的問題。如果你添加一個類型提示.<Pair<T1,T2>>flatMap,它編譯得很好。

如果我可以提出一個不同的做法,考慮讓笛卡兒積不做整個流和收集,但僅僅是flatMap一個幫手:

static <T1, T2, R> Function<T1, Stream<R>> crossWith(
     Supplier<? extends Stream<T2>> otherSup, 
     BiFunction<? super T1, ? super T2, ? extends R> combiner 
) { 
    return t1 -> otherSup.get().map(t2 -> combiner.apply(t1, t2)); 
} 

現在你只需要創建一個Pair如果你想結果包含Pair S和您可以通過應用flatMap幾次做了更高階的笛卡爾乘積:

List<String> letters = Arrays.asList("A", "B", "C"); 
List<Integer> numbers = Arrays.asList(1, 2, 3); 

List<Pair<String, Integer>> board = letters.stream() 
       .flatMap(crossWith(numbers::stream, Pair::new)) 
       .collect(toList()); 


List<String> ops = Arrays.asList("+", "-", "*", "/"); 

List<String> combinations = letters.stream() 
       .flatMap(crossWith(ops::stream, String::concat)) 
       .flatMap(crossWith(letters::stream, String::concat)) 
       .collect(toList()); // triple cartesian product 
+0

通過這種方式,調用'flatMap'的次數是在編譯時確定的。 – stanleyerror

+0

我的意思是說,我可能知道集合並手動調用'flatMap',而不是確定在運行時調用'flatMap'的時間,並獲得每個存儲在'tuple'中的'tuple'的通用集合。 – stanleyerror

+1

我不知道我明白。你能更清楚地描述你正試圖解決的問題嗎? – Misha

2

下面是推廣到了NUM的情況下的解決方案必需的flatMap應用程序(即,即產品的順序)在編譯時不知道。

BinaryOperator<Function<String,Stream<String>>> kleisli = (f,g) -> s -> f.apply(s).flatMap(g); 

List<String> cartesian(int n, Collection<String> coll) { 
    return coll.stream() 
      .flatMap(IntStream.range(1, n).boxed() 
        .map(_any -> crossWith(coll::stream, String::concat)) // create (n-1) appropriate crossWith instances 
        .reduce(s -> Stream.of(s), kleisli)     // compose them sequentially 
        )              // flatMap the stream with the entire function chain 
      .collect(toList()); 
} 

你會發現這是如何工作在my own blog的詳細信息。

+0

請參閱[這個問題](http://stackoverflow.com/q/32131987/4856258),這是更廣泛的。 –