I doubt this is fastest, or most efficient by any measure, but I like it (and it's more general).
This basically says to get all combinations of size k from a (sorted) list of n elements, take each of the n-k+1 first elements in turn, and append all combinations of size k-1 from the elements in the list that come after it.
To terminate the recursion, if k=1, just return a list of singleton lists of each of the elements.
To make that concrete, in your example, it does:
"A", with all possible combinations of 3 letters from "B"-"J" appended
along with
"B", with all possible combinations of 3 letters from "C"-"J" appended
along with
"C", with all possible combinations of 3 letters from "D"-"J" appended
...
"F", with all possible combinations of 3 letters from "G"-"J" appended
along with
"G", with all possible combinations of 3 letters from "H"-"J" appended (there is only 1)
To get all possible combinations of 3 letters from "B"-"J", it does
"B", with all possible combinations of 2 letters from "C"-"J" appended
along with
"C", with all possible combinations of 2 letters from "D"-"J" appended
etc
The combinations are produced in lexographical order, with respect to the initial ordering of the list.
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class Combinatorics {
/**
* Computes all combinations of items of size <code>size</code>
* Assumes that items contains no replicates<
* @param items
* @param size
* @return A List of all possible Lists of items, each List of size <code>size</code>.
*/
public static <T extends Comparable<? super T>> List<List<T>> combinations(List<T> items, int size) {
if (size == 1) {
List<List<T>> result = new ArrayList<>();
for (T item : items) {
result.add(Collections.singletonList(item));
}
return result ;
}
List<List<T>> result = new ArrayList<>();
for (int i=0; i <= items.size() - size; i++) {
T firstItem = items.get(i);
List<List<T>> additionalItems = combinations(items.subList(i+1, items.size()), size-1) ;
for (List<T> additional : additionalItems) {
List<T> combination = new ArrayList<>();
combination.add(firstItem);
combination.addAll(additional);
result.add(combination);
}
}
return result ;
}
public static void main(String[] args) {
List<String> values = Arrays.asList("A", "C", "B", "D", "E", "F", "G", "H", "I", "J");
List<List<String>> allCombinations = combinations(values, 4);
for (List<String> combination : allCombinations) {
System.out.println(combination);
}
System.out.println(allCombinations.size() + " total combinations");
}
}