问题
I want this method to work for any given number of arguments, i can do that with code generation(with a lot of ugly code), can it be done with recursion? if so how? I understand recursion, but i dont know how to write this.
private static void allCombinations(List<String>... lists) {
if (lists.length == 3) {
for (String s3 : lists[0]) {
for (String s1 : lists[1]) {
for (String s2 : lists[2]) {
System.out.println(s1 + "-" + s2 + "-" + s3);
}
}
}
}
if (lists.length == 2) {
for (String s3 : lists[0]) {
for (String s1 : lists[1]) {
System.out.println(s1 + "-" + s3);
}
}
}
}
回答1:
Here is a simple recursive implementation:
private static void allCombinations(List<String>... lists) {
allCombinations(lists, 0, "");
}
private static void allCombinations(List<String>[] lists, int index, String pre) {
for (String s : lists[index]) {
if (index < lists.length - 1) {
allCombinations(lists, index + 1, pre + s + "-");
}else{
System.out.println(pre + s);
}
}
}
回答2:
Do you particularly need it to be recursive? I'd make it non-recursive but still not special case things:
public static void allCombinations(List<String>... lists) {
int[] indexes = new int[lists.length];
while (incrementIndexes(lists, indexes)) {
StringBuilder builder = new StringBuilder();
for (int i=0; i < indexes.length; i++) {
if (i != 0) {
builder.append("-");
}
builder.append(lists[i].get(indexes[i]));
}
System.out.println(builder);
}
}
private static boolean incrementIndexes(List<String>[] lists, int[] indexes) {
for (int depth = indexes.length-1; depth >= 0; depth--) {
indexes[depth]++;
if (indexes[depth] != lists[depth].size()) {
return true;
}
// Overflowed this index. Reset to 0 and backtrack
indexes[depth] = 0;
}
// Everything is back to 0. Finished!
return false;
}
回答3:
Here's a generalised recursive version. It complains about unchecked generic array creation in the test code, but the permute code itself is okay:
import java.util.*;
public class Test
{
public interface Action<T> {
void execute(Iterable<T> values);
}
public static void main(String[] args) {
List<String> first = Arrays.asList(new String[]{"1", "2", "3"});
List<String> second = Arrays.asList(new String[]{"a", "b", "c"});
List<String> third = Arrays.asList(new String[]{"x", "y"});
Action<String> action = new Action<String>() {
@Override public void execute(Iterable<String> values) {
StringBuilder builder = new StringBuilder();
for (String value : values) {
if (builder.length() != 0) {
builder.append("-");
}
builder.append(value);
}
System.out.println(builder);
}
};
permute(action, first, second, third);
}
public static <T> void permute(Action<T> action, Iterable<T>... lists) {
Stack<T> current = new Stack<T>();
permute(action, lists, 0, current);
}
public static <T> void permute(Action<T> action, Iterable<T>[] lists,
int index, Stack<T> current) {
for (T element : lists[index]) {
current.push(element);
if (index == lists.length-1) {
action.execute(current);
} else {
permute(action, lists, index+1, current);
}
current.pop();
}
}
}
回答4:
here's my recursive solution with correct ordering, based on Rasmus' solution. it works only if all lists are of same size.
import java.util.Arrays;
import java.util.List;
public class Test {
public static void main(String[] args) {
List<String> first = Arrays.asList(new String[]{"1", "2", "3"});
List<String> second = Arrays.asList(new String[]{"a", "b", "c"});
List<String> third = Arrays.asList(new String[]{"x", "y", "z"});
allCombinations (first, second, third);
}
private static void allCombinations(List<String>... lists) {
allCombinations(lists, 1, "");
}
private static void allCombinations(List<String>[] lists, int index, String pre) {
int nextHop = hop(index, lists.length-1);
for (String s : lists[index]) {
if (index != 0) {
allCombinations(lists, nextHop, pre + s + "-");
} else System.out.println(pre + s);
}
}
private static int hop(int prevIndex, int maxResult){
if (prevIndex%2 == 0){
return prevIndex-2;
} else {
if (prevIndex == maxResult)
return prevIndex-1;
int nextHop = prevIndex+2;
if (nextHop > maxResult){
return maxResult;
} else return nextHop;
}
}
}
a "correct ordering" solution that allows lists of different sizes will have to start from the last list and work it's way backwards to the first list (lists[0]), appending the element at either beginning or end of the "pre" string and passing it onward. again, the first list will print the result. I'd have coded that, but lunch is ready and girlfriend is beginning to dislike stackoverflow...
来源:https://stackoverflow.com/questions/207889/recursion-instead-of-multi-loops