- Initialize an array (
A
) to the first 5 indices. (0,1,2,3,4)
- Move the last possible index in A to the next position.
A[k]++
- Move the following indices to the following successive positions. (
A[k+1] = A[k] + 1
, ...). If some index would become too large, try with an earlier index in step 2.
- Yield the elements at the current indices in
A
.
- If possible, repeat from step 2.
Implemented as an iterator:
public class CombinationIterator
implements Iterable>,
Iterator> {
private List items;
private int choose;
private boolean started;
private boolean finished;
private int[] current;
public CombinationIterator(List items, int choose) {
if (items == null || items.size() == 0) {
throw new IllegalArgumentException("items");
}
if (choose <= 0 || choose > items.size()) {
throw new IllegalArgumentException("choose");
}
this.items = items;
this.choose = choose;
this.finished = false;
}
public Iterator> iterator() {
return this;
}
public boolean hasNext() {
return !finished;
}
public List next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
if (current == null) {
current = new int[choose];
for (int i = 0; i < choose; i++) {
current[i] = i;
}
}
List result = new ArrayList(choose);
for (int i = 0; i < choose; i++) {
result.add(items.get(current[i]));
}
int n = items.size();
finished = true;
for (int i = choose - 1; i >= 0; i--) {
if (current[i] < n - choose + i) {
current[i]++;
for (int j = i + 1; j < choose; j++) {
current[j] = current[i] - i + j;
}
finished = false;
break;
}
}
return result;
}
public void remove() {
throw new UnsupportedOperationException();
}
}
Equivalent in C#, using an Iterator method:
public IEnumerable> Combinations(IEnumerable items, int choose)
{
if (items == null) throw new ArgumentNullException("items");
var itemsList = items.ToList();
int n = itemsList.Count;
if (n < 1) throw new ArgumentException("Must contain at least one item.", "items");
if (choose <= 0 || choose >= n) throw new ArgumentOutOfRangeException("choose");
var indices = Enumerable.Range(0, choose).ToArray();
bool moreWork = true;
while (moreWork)
{
yield return indices.Select(i => itemsList[i]).ToList();
moreWork = false;
for (int i = choose - 1; i >= 0; i--)
{
if (indices[i] < n - choose + i)
{
indices[i]++;
for (int j = i + 1; j < choose; j++)
{
indices[j] = indices[i] - i + j;
}
moreWork = true;
break;
}
}
}
}