I want to compute the cartesian product of an arbitrary number of nonempty sets in Java.
I\'ve wrote that iterative code...
public s
I've written a solution that doesn't require you to fill up a large collection in memory. Unfortunately, the code required is hundreds of lines long. You may have to wait until it appears in the Guava project (https://github.com/google/guava), which I hope will be by the end of the year. Sorry. :(
Note that you may not need such a utility if the number of sets you're cartesian-producting is a fixed number known at compile time -- you could just use that number of nested for loops.
EDIT: the code is released now.
Sets.cartesianProduct()
I think you'll be very happy with it. It only creates the individual lists as you ask for them; doesn't fill up memory with all MxNxPxQ of them.
If you want to inspect the source, it's here.
Enjoy!
Index-based solution
Working with the indices is a simple alternative that is fast and memory-efficient and can handle any number of sets. Implementing Iterable allows easy use in a for-each loop. See the #main method for a usage example.
public class CartesianProduct implements Iterable<int[]>, Iterator<int[]> {
private final int[] _lengths;
private final int[] _indices;
private boolean _hasNext = true;
public CartesianProduct(int[] lengths) {
_lengths = lengths;
_indices = new int[lengths.length];
}
public boolean hasNext() {
return _hasNext;
}
public int[] next() {
int[] result = Arrays.copyOf(_indices, _indices.length);
for (int i = _indices.length - 1; i >= 0; i--) {
if (_indices[i] == _lengths[i] - 1) {
_indices[i] = 0;
if (i == 0) {
_hasNext = false;
}
} else {
_indices[i]++;
break;
}
}
return result;
}
public Iterator<int[]> iterator() {
return this;
}
public void remove() {
throw new UnsupportedOperationException();
}
/**
* Usage example. Prints out
*
* <pre>
* [0, 0, 0] a, NANOSECONDS, 1
* [0, 0, 1] a, NANOSECONDS, 2
* [0, 0, 2] a, NANOSECONDS, 3
* [0, 0, 3] a, NANOSECONDS, 4
* [0, 1, 0] a, MICROSECONDS, 1
* [0, 1, 1] a, MICROSECONDS, 2
* [0, 1, 2] a, MICROSECONDS, 3
* [0, 1, 3] a, MICROSECONDS, 4
* [0, 2, 0] a, MILLISECONDS, 1
* [0, 2, 1] a, MILLISECONDS, 2
* [0, 2, 2] a, MILLISECONDS, 3
* [0, 2, 3] a, MILLISECONDS, 4
* [0, 3, 0] a, SECONDS, 1
* [0, 3, 1] a, SECONDS, 2
* [0, 3, 2] a, SECONDS, 3
* [0, 3, 3] a, SECONDS, 4
* [0, 4, 0] a, MINUTES, 1
* [0, 4, 1] a, MINUTES, 2
* ...
* </pre>
*/
public static void main(String[] args) {
String[] list1 = { "a", "b", "c", };
TimeUnit[] list2 = TimeUnit.values();
int[] list3 = new int[] { 1, 2, 3, 4 };
int[] lengths = new int[] { list1.length, list2.length, list3.length };
for (int[] indices : new CartesianProduct(lengths)) {
System.out.println(Arrays.toString(indices) //
+ " " + list1[indices[0]] //
+ ", " + list2[indices[1]] //
+ ", " + list3[indices[2]]);
}
}
}
Using Google Guava 19 and Java 8 is very simple:
Say you have the List of all arrays you want to associate...
public static void main(String[] args) {
List<String[]> elements = Arrays.asList(
new String[]{"John", "Mary"},
new String[]{"Eats", "Works", "Plays"},
new String[]{"Food", "Computer", "Guitar"}
);
// Create a list of immutableLists of strings
List<ImmutableList<String>> immutableElements = makeListofImmutable(elements);
// Use Guava's Lists.cartesianProduct, since Guava 19
List<List<String>> cartesianProduct = Lists.cartesianProduct(immutableElements);
System.out.println(cartesianProduct);
}
The method to make the list of immutable lists is as follows:
/**
* @param values the list of all profiles provided by the client in matrix.json
* @return the list of ImmutableList to compute the Cartesian product of values
*/
private static List<ImmutableList<String>> makeListofImmutable(List<String[]> values) {
List<ImmutableList<String>> converted = new LinkedList<>();
values.forEach(array -> {
converted.add(ImmutableList.copyOf(array));
});
return converted;
}
The output is as follows:
[
[John, Eats, Food], [John, Eats, Computer], [John, Eats, Guitar],
[John, Works, Food], [John, Works, Computer], [John, Works, Guitar],
[John, Plays, Food], [John, Plays, Computer], [John, Plays, Guitar],
[Mary, Eats, Food], [Mary, Eats, Computer], [Mary, Eats, Guitar],
[Mary, Works, Food], [Mary, Works, Computer], [Mary, Works, Guitar],
[Mary, Plays, Food], [Mary, Plays, Computer], [Mary, Plays, Guitar]
]