Building on a very simple and elegant recursive solution provided by
Adam under a different question: 'Algorithm to return all combinations
of k elements from n', which you can find elsewhere.
Adam's answer provides, however, for obtaining all combinations from
a given set, which doesn't exactly fit the question under which his
answer was given, but I found his answer suited the purpose of my
research perfectly. I look for value wherever I might find it. And
it does fit this present question.
I developed the following program using Open Arrays in Free Pascal
to produce all combinations of items in any given array. The open array
allows for an arbitrary and dynamically variable number of items,
and each item can be any kind of variable or record. This program has
items of long integers, but could also be used for pointers to other
variables. I used it that way to determine the most efficient way of
cutting metal bars into various lengths of shorter bars, by examining
the various possible combinations of shorter bars of different lengths
which fit into the raw material bars.
The procedure combo recurses once for every possible combination,
but the depth of recursion is only one level deeper than the number
of items in the 'pending' source array. Passing the parameters to
the combo procedure by reference is not necessary, but doing so
cuts the operational memory requirement nearly in half.
program combinata;
uses
SYSUTILS;
type
combarry = array of longint;
var
testc, testp :combarry;
procedure produce (var cmb :combarry);
var x :integer;
begin
for x := 0 to length(cmb)-1 do begin
if x > 0 then write(',');
write(cmb[x]:0);
end;
writeln;
end;
procedure combo (var current, pending :combarry);
var
x, len :integer;
newcurrent, newpending :combarry;
begin
if length(pending) = 0 then
if length(current) > 0 then produce(current) else
else begin
{append 1st element of pending as the last element on current}
newcurrent := current;
len := length(newcurrent);
setlength(newcurrent,len+1);
newcurrent[len] := pending[0];
{remove the first element from pending}
len := length(pending) - 1;
setlength(newpending,len);
for x := len downto 1 do newpending[x-1] := pending[x];
combo(newcurrent,newpending);
combo(current,newpending);
end;
end;
begin
setlength(testc,0);
setlength(testp,4);
testp[0] := 5;
testp[1] := 10;
testp[2] := 15;
testp[3] := 20;
combo(testc, testp);
writeln('*');
end.
Running this produces:
5,10,15,20
5,10,15
5,10,20
5,10
5,15,20
5,15
5,20
5
10,15,20
10,15
10,20
10
15,20
15
20
*