I have a problem that is really kind of a general programming question, but my implementation is in Java, so I will provide my examples that way
I have a class like
You can generate the combinations recursively.
public class Main {
public static void main(String[] args) {
int[][] arr = new int[][] { { 1, 2, 3 }, { 3, 2 }, { 5, 6, 7 } };
cartesianProduct(arr, 0, new int[arr.length]);
}
private static void cartesianProduct(int[][] arr, int level, int[] cp) {
if (level == arr.length) {
for (int x : cp)
System.out.print(x + " ");
System.out.println();
return;
}
for (int i = 0; i < arr[level].length; i++) {
cp[level] = arr[level][i];
cartesianProduct(arr, level + 1, cp);
}
}
}
Output :
1 3 5
1 3 6
1 3 7
1 2 5
1 2 6
1 2 7
2 3 5
2 3 6
2 3 7
2 2 5
2 2 6
2 2 7
3 3 5
3 3 6
3 3 7
3 2 5
3 2 6
3 2 7
Guava has a utility method which returns a cartesian product of the given list of sets: Sets.cartesianProduct.
I know it's long after you needed the answer, but somehow I can't refrain from noticing that one could switch to Groovy, at least for some part of a Java application, and write a wrapper class to match the desired interface. The Groovy code for such permutations is
myListOfLists.combinations()
Ever since I started using Groovy in my Java applications, it's much faster to write them and way more interesting to debug/profile them (ehem...)
You could also solve this really easily with Functional Java's List monad:
import fj.data.List;
public class cartesian {
public static void main(String[] args) {
List<String> foo = List.list("a", "b");
List<Integer> bar = List.list(1,2,3);
List<Float> baz = List.list(0.2f,0.4f,0.3f);
List<P3<String, Integer, Float>>
// the Cartesian product is assembled into a list of P3's
result = foo.bind(bar, baz, P.<String, Integer, Float>p3());
String out = Show.listShow(Show.p3Show(Show.stringShow, Show.intShow, Show.floatShow))
.showS(result);
System.out.println(out);
}
}
Take a look at the following two methods, they do exactly what you asked for. I wrote them to be generic, it doesn't matter how long your lists are or how many keys exist in the map, the combinations generated are correct.
The code below is iterative, based on the algorithm of Python's itertools.product() function for calculating the Cartesian product of a list of lists.
public String[][] allUniqueCombinations() {
List<String> labels = new ArrayList<String>();
List<List<String>> lists = new ArrayList<List<String>>();
for (Map.Entry<String, Vector<String>> entry : dataStructure.entrySet()) {
labels.add(entry.getKey());
lists.add(entry.getValue());
}
List<List<String>> combinations = product(lists);
int m = combinations.size() + 1;
int n = labels.size();
String[][] answer = new String[m][n];
for (int i = 0; i < n; i++)
answer[0][i] = labels.get(i);
for (int i = 1; i < m; i++)
for (int j = 0; j < n; j++)
answer[i][j] = combinations.get(i-1).get(j);
return answer;
}
private List<List<String>> product(List<List<String>> lists) {
List<List<String>> result = new ArrayList<List<String>>();
result.add(new ArrayList<String>());
for (List<String> e : lists) {
List<List<String>> tmp1 = new ArrayList<List<String>>();
for (List<String> x : result) {
for (String y : e) {
List<String> tmp2 = new ArrayList<String>(x);
tmp2.add(y);
tmp1.add(tmp2);
}
}
result = tmp1;
}
return result;
}
I tested them with the example in the question:
LinkedHashMap<String, Vector<String>> sample =
new LinkedHashMap<String, Vector<String>>();
Vector<String> v1 = new Vector<String>();
v1.add("1"); v1.add("2"); v1.add("3");
Vector<String> v2 = new Vector<String>();
v2.add("3"); v2.add("2");
Vector<String> v3 = new Vector<String>();
v3.add("5"); v3.add("6"); v3.add("7");
sample.put("foo", v1);
sample.put("bar", v2);
sample.put("baz", v3);
Foo foo = new Foo(sample);
String[][] ans = foo.allUniqueCombinations();
for (String[] row : ans)
System.out.println(Arrays.toString(row));
The answer that gets printed is the expected (although the combinations appear in a different order):
[foo, bar, baz]
[1, 3, 5]
[1, 3, 6]
[1, 3, 7]
[1, 2, 5]
[1, 2, 6]
[1, 2, 7]
[2, 3, 5]
[2, 3, 6]
[2, 3, 7]
[2, 2, 5]
[2, 2, 6]
[2, 2, 7]
[3, 3, 5]
[3, 3, 6]
[3, 3, 7]
[3, 2, 5]
[3, 2, 6]
[3, 2, 7]
A LinkedHashMap of Vectors of Strings is ... - troublesome. I had to spend much time in converting a solution to use it, but in the end, I don't produce an ArrayOfArrays, but a List of List and keep the last step to the reader.
import java.util.*;
/**
CartesianProductLHM
*/
public class CartesianProductLHM
{
LinkedHashMap <String, Vector<String>> dataStructure;
public CartesianProductLHM (final String[] data) {
dataStructure = new LinkedHashMap <String, Vector<String>> ();
for (String str : data)
{
String [] kv = str.split (":");
String [] values = kv[1].split (",");
Vector <String> v = new Vector <String> ();
for (String s: values) {
v.add (s);
// System.out.print (s);
}
// System.out.println ("\n---");
dataStructure.put (kv[0], v);
}
// System.out.println (" --- --- ---");
}
List <String> getCombiFor (final int i, final List <List <String>> livs)
{
List <String> ls = new ArrayList <String> ();
if (! livs.isEmpty ()) {
List <String> vs = livs.remove (0);
int idx = i % vs.size ();
String elem = vs.get (idx);
ls.add (elem);
ls.addAll (getCombiFor (i / vs.size (), livs));
}
return ls;
}
List <String> getOuterCombiFor (int i, List <List <String>> coll)
{
List <String> ls = new ArrayList <String> ();
if (! coll.isEmpty ()) {
List <List <String>> livs = new ArrayList <List <String>> ();
for (List<String> li : coll)
{
livs.add (li);
}
ls.addAll (getCombiFor (i, livs));
}
return ls;
}
public List <List <String>> allUniqueCombinations () {
Collection <Vector <String>> li = dataStructure.values ();
List <List <String>> lls = new ArrayList <List <String>> ();
for (Vector <String> vs : li) {
List <String> l = new ArrayList <String> ();
for (String s : vs) {
l.add (s);
}
lls.add (l);
}
int count = 1;
for (Vector <String> vec: li) {
count *= vec.size ();
}
List <List <String>> result = new ArrayList <List <String>> ();
for (int i = 0; i < count; ++i)
{
List <String> l = getOuterCombiFor (i, lls);
result.add (l);
}
return result;
}
public static void main (String args[])
{
String[] arr = {"foo:1,2,3", "bar:a,b", "baz:5,6,7"};
CartesianProductLHM cp = new CartesianProductLHM (arr);
List <List <String>> lls = cp.allUniqueCombinations ();
for (List <String> ls : lls)
{
for (String s : ls)
System.out.print (s + "\t");
System.out.println ();
}
}
}
Well - yes, and I parse some test data.
The main idea is, that you have some Lists (abc, 12, defg, ...) and you have 3 possibilities at pos 0, 2 at pos 1, 4 at pos 3 and so on, so 3*2*4 combinations so far.
From the numbers 0 to 23 you can pick from each sublist with modulo, and hand the rest of the number divided by the size of the previous list and the remaining lists recursively to the procedure, until there is no list left.