2015-07-13 16 views
8

Ngay bây giờ tôi chỉ có thể thực hiện các sản phẩm Descartes của hai bộ sưu tập, đây là mã:Thực hiện sản phẩm Descartes của bộ sưu tập của 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); 
} 

Mã này hoạt động tốt trong IntelliJ, nhưng không phải trong Eclipse (cả với mức độ tuân thủ trình biên dịch là 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>) 

đây là 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; 
    } 

} 

Cách khắc phục lỗi này?

Có cách nào thanh lịch để triển khai Sản phẩm Descartes của một số bộ sưu tập không? (giả sử chúng ta có lớp tuple)

+0

Whats 'Pair'? bạn có thể cho nhập khẩu cho điều đó không? – Shahzeb

Trả lời

8

Eclipse có vấn đề với suy luận kiểu. Nếu bạn thêm gợi ý loại .<Pair<T1,T2>>flatMap, nó sẽ biên dịch tốt.

Nếu tôi có thể đề nghị một cách tiếp cận khác nhau, hãy xem xét làm Tích Descartes của bạn không làm toàn bộ dòng và bộ sưu tập mà chỉ đơn thuần là một helper cho 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)); 
} 

Bây giờ bạn chỉ cần tạo một Pair nếu bạn muốn kết quả để chứa Pair s và bạn có thể làm một sản phẩm bậc cao Descartes bằng cách áp dụng flatMap nhiều lần:

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

Bằng cách này, thời gian gọi 'flatMap' được xác định tại thời gian biên dịch. – stanleyerror

+0

Tôi có nghĩa là, tôi có thể biết các bộ sưu tập và gọi 'flatMap' theo cách thủ công, thay vì xác định thời gian gọi' flatMap' khi chạy, và nhận được một bộ sưu tập 'tuple' của mỗi lưu trữ trong một' tuple'. – stanleyerror

+1

Tôi không chắc tôi hiểu. Bạn có thể mô tả rõ ràng hơn vấn đề mà bạn đang cố gắng giải quyết không? – Misha

2

Dưới đây là một giải pháp mà khái quát cho trường hợp đó, num ber of requisite flatMap-ứng dụng (i. e. thứ tự của sản phẩm) không được biết tại thời gian biên dịch.

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

Bạn sẽ tìm thấy chi tiết về cách thức hoạt động tại my own blog.

+0

Xem [câu hỏi này] (http://stackoverflow.com/q/32131987/4856258) thậm chí còn tổng quát hơn. –

Các vấn đề liên quan