Right now I can only implement the Cartesian product of two collections, here is the code:
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); }
This code works fine in IntelliJ, but not in Eclipse. Both with compiler compliance level of 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>)
Here is 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; } }
How to fix this error?
Is there an elegant way to implement the Cartesian product of several collections? Suppose we have class tuple
.
Advertisement
Answer
Eclipse has problems with type inference. If you add a type hint .<Pair<T1,T2>>flatMap
, it compiles fine.
If I may suggest a different approach, consider making your cartesianProduct not do the entire stream and collection but merely be a helper for 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)); }
Now you only need to create a Pair
if you want the result to contains Pair
s and you can do a higher-order cartesian product by applying flatMap
several times:
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