{$mode delphi}
{$rangeChecks on}
{$APPTYPE CONSOLE}
Function factorial(n:integer):qword;
begin
If (n <= 1) Then exit (1) Else exit(n * factorial(n - 1))
End;
type Arrays<T>=object
public
original:array of T;
arr:array of array of T;
ar:array of T;
end;
function clean<T>(arr:T):T;
var
count:int32=0;
i,j,n:int32;
temp:T;
begin
temp:=nil;
n:=high(arr);
setlength(temp,length(arr));
for i :=0 to n do
begin
for j:=0 to count do if (arr[i]=temp[j]) then break;
if (j=count) then
begin
temp[count]:=arr[i];
count:=count+1;
end;
end;
setlength(temp,count);
exit(temp);
End;
procedure combinations<T>(arr:array of T;n,r,index:int32;_data: array of T;var _out: Arrays<T>;i:int32;var ct:int32);
var
j:int32;
begin
If (index=r) Then
begin
ct:=ct+1;
For j:=0 To r-1 do
begin
_out.arr[ct,j+1]:= _data[j];
end;
exit;
end;
If (i>=n) Then exit;
_data[index] := arr[i];
combinations<T>(arr,n,r,index + 1,_data,_out,i+1,ct);
combinations<T>(arr,n,r,index,_data,_out,i+1,ct);
End;
procedure getcombinations<T>(f:array of T;r:int32;var ret:Arrays<T>);
type aa=array of T;
var
n,i,j,counter:integer;
k:qword;
ct:int32=0;
_data:array of T=nil;
_ret :Arrays<T>=(arr:nil);
c:aa=nil;
begin
setlength(c,length(f));
for i:=0 to high(f) do
c[i]:=f[i];
c:=clean<aa>(c);
counter:=0;
n:=length(c);
setlength(_data,r);
k:=factorial(n) div (factorial(r)*factorial(n-r));
setlength(_ret.arr,k+1,r+1);
combinations<T>(c,high(c)+1,r,0,_data,_ret,0,ct);
ret:=_ret;
for i:=1 to high(_ret.arr) do
begin
for j:=1 to high(_ret.arr[0]) do
begin
counter:=counter+1;
setlength(ret.ar,counter);
ret.ar[counter-1]:=_ret.arr[i,j];
end;
end;
//optional for showing original array
setlength(ret.original,length(f));
for i:=0 to high(f) do
ret.original[i]:=f[i];
End;
procedure show<T>(ret:Arrays<T>);
var i,j:integer;
var counter:integer=0;
begin
writeln('Original set:');
for i:=0 to high(ret.original) do write (ret.original[i],' ');
writeln;writeln;
for i:=1 to high(ret.arr) do
begin
for j:=1 to high(ret.arr[0]) do
begin
counter:=counter+1;
write(ret.ar[counter-1],' ');
end;
writeln;
end;
writeln;
writeln('number of combinations: ',counter div high(ret.arr[0]));
End;
var
a:array of string=['apple','orange','pear','peach','cherry','lemon'];
ret:Arrays<string>=(ar:nil);
retb:Arrays<integer>=(ar:nil);
begin
getcombinations<string>(a,4,ret);
show<string>(ret);
getcombinations<integer>([7,2,9,0,1,7,7,2],3,retb);
writeln('------------------------- ');
show<integer>(retb);
writeln('Press enter to end . . .');
readln;
end.