Thanks, AgentSam. Very nice code!
I'm not sure it's the most "elegant" solution, but I always work on Einstein's principle "Keep it as simple as possible, but no simpler."
An elegant solution is to run a permutation on the bits. So I did this, and it's ten times slower than the simple numeric method. That's understandable, because permutations are complex, whereas sticking a number in a field is simple and processor-friendly.
I modified the computation routine either to use or not use and array. In both cases I have used Phaelax's sensible suggestion to start from the lowest and go to the highest possible numbers.
procedure GenerateList(const bits:cardinal; commas: boolean; var tsl: TStringList; usearray:boolean = true);
var i : integer;
mask : array[0..MaxArray] of Masker; // only used in array method
n,f : TTime;
m : Masker;
start, finish : Masker;
iHours, IMinutes, iSeconds, iMillisecs : word;
begin
if not assigned(tsl) then exit; // avoid null pointer
tsl.Clear; // clear the stringlist
n := Time; // start time
// get lowest and highest possible numbers
start.st := []; finish.st := [];
for i := 0 to bits-1 do include(start.st,i);
for i := 15 downto 16-bits do include(finish.st,i);
tsl.Add(format('start %d end %d',[start.number,finish.number]));
if usearray then //--------------------------------------------------------------
begin
fillchar(mask, sizeof(mask),#0); // clear the array to zero
// first fill the array with the numbers from start to finish
for i := start.number to finish.number do begin
mask[i].number := i;
end;
// zero those with the wrong number of bits
for i := start.number to finish.number do if CountBits(mask[i])<>bits then mask[i].number := 0;
// now generate the output strings according to whether we need commas
for i := start.number to finish.number do if mask[i].number <> 0 then tsl.AddObject(GenString(mask[i],commas), pointer(mask[i].number));
end // using array //-----------------------------------------------------------
else
begin // not using array //------------------------------------------------------
for i := start.number to finish.number do begin
m.number := i;
if countbits(m)=bits then tsl.AddObject(GenString(m,commas), pointer(m.number));
end;
end; //--------------------------------------------------------------------------
f := time;
n := f-n;
decodetime(n,ihours,iminutes,iSeconds,iMillisecs);
tsl.Add(format('time %d seconds %d milliseconds',[iseconds,iMillisecs]));
end;
There is no significant difference between the run time of the two approaches - 18 milliseconds on a AMD quadcore and 15 milliseconds on an i5. Most of the cost here is adding to the stringlist. Using a TList and not outputting strings would be radically faster.
This code is completely OS-agnostic, and will run on Windows, Android, OS X, or iOS.
-- Jim DO IT FASTER, EASIER AND BETTER WITH AppGameKit FOR PASCAL