I took it as a challenge to see if the new Java 8 APIs help with such problems. So here is my solution to the problem:
public class CombinatorIterator implements Iterator<Collection<String>> { private final String[][] arrays; private final int[] indices; private final int total; private int counter; public CombinatorIterator(Collection<String[]> input) { arrays = input.toArray(new String[input.size()][]); indices = new int[arrays.length]; total = Arrays.stream(arrays).mapToInt(arr -> arr.length) .reduce((x, y) -> x * y).orElse(0); counter = 0; } @Override public boolean hasNext() { return counter < total; } @Override public Collection<String> next() { List<String> nextValue = IntStream.range(0, arrays.length) .mapToObj(i -> arrays[i][indices[i]]).collect(Collectors.toList()); //rolling carry over the indices for (int j = 0; j < arrays.length && ++indices[j] == arrays[j].length; j++) { indices[j] = 0; } counter++; return nextValue; } }
Please note that I do not use the map as input, since in fact the map keys do not play any role. You can use map.values() though to pass input to an iterator. With the following test code:
List<String[]> input = Arrays.asList( new String[] {"such", "nice", "question"}, new String[] {"much", "iterator"}, new String[] {"very", "wow"} ); Iterator<Collection<String>> it = new CombinatorIterator(input); it.forEachRemaining(System.out::println);
the output will be:
[such, much, very] [nice, much, very] [question, much, very] [such, iterator, very] [nice, iterator, very] [question, iterator, very] [such, much, wow] [nice, much, wow] [question, much, wow] [such, iterator, wow] [nice, iterator, wow] [question, iterator, wow]