Displaying Combinations

I have Win98 and D4. A previously asked question on displaying  combinations was done sometime during the month of  May 99.  I would like to see the solution again.   Comment : This newEE  system is so slow leafing backwards through the previous solutions offered that it may take me days to get back to there. And yes I have used the NEW search engine but no solution to this topic  is offered in Delphi.

RWilson's contribution  was, as I have copied from the locked Question:
      var
        I : integer;
        Count : Integer;
        CombinationSize : Integer;
        Combinations : TStringlist;
        TheItems : TStringList; // Set of items;

  procedure OutputCombination(Depth : Integer; state : string);
      var
        I : integer;
      begin
        if depth > 0 then
          begin
            for I := CombinationSize - Depth to Count - Depth + 1 do
              OutputCombination(Count, Depth - 1, State + ','+TheItems[I]);
          end
        else
          Combinations.add(state);
      end;

      begin
        Count := 10;
        CombinationSize := 4;
        Combinations := TStringList.Create;
        TheItems := TStringList.Create;
        AddItemsToSet(TheItems); // fill the set here...

        for I := 1 to Count - CombinationSize + 1 do
          OutputCombination(CombinationSize - 1, TheItems[i]);
      end;

Comment: is there a better update???????

Delphi3
       

LVL 4
delphi3Asked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

delphi3Author Commented:
Edited text of question.
0
LischkeCommented:
Hi Delphi3,

here's another implementation for your problem. I hope it is what you are looking for as I don't know the original question. I also don't know what you consider as being better. The code below takes a range of characters and constructs all possible combinations from these chars.

type
  TCharRange = set of Char;

procedure CreateCombinations(Range: TCharRange; Depth: Cardinal; List: TStrings);

var
  Exclusion: TCharRange;

  procedure ConstructLevel(Level: Cardinal; Item: String);

  var
    I: Char;
     
  begin
    if Level > 0 then
    begin
      for I := #0 to #255 do
        if I in (Range - Exclusion) then
        begin
          Include(Exclusion, I);
          ConstructLevel(Level - 1, I + Item);
          Exclude(Exclusion, I);
        end;
    end
    else List.Add(Item);
  end;

begin
  List.Clear;
  if Depth > 0 then
  begin
    Exclusion := [];
    ConstructLevel(Depth, '');
  end;
end;

procedure TMainForm.Button5Click(Sender: TObject);

begin
  CreateCombinations(['A'..'Z'], 3, ListBox1.Items);
end;

The Depth parameter determines the length of the result strings. This parameter must be less or equal the number of elements in the range of characters. If you want to allow duplicates in the result then replace:

if I in (Range - Exclusion) then...

by:

if I in Range then...

Ciao, Mike
0
sburckCommented:
My answer to the question, which is still waiting to graded, takes a string, and builds a combination of that string according to an index.

For instance permutestring('ABC',1) would return 'ABC', while
('ABC',2) would return 'ACB', up to ('ABC',6) which would return 'CBA'.

It has advantages and disadvantages over the other offers.  It requires very little memory, as it doesn't store all the possible combinations (on large strings, very, as there are lots of combinations on very large numbers).  On the other hand, for small numbers, it takes more time, especially when up against lookups in pre-calculated combination tables.

It lacks error checking (don't call it with ('ABC',7) for instance), and is limited to 21 digits long strings (the limit imposed by the size of INT64).

function excited_n(n : int64) : int64;
var
     i : integer;
begin
       result := 1;
       if n < 2 then
            exit;
       for i:=2 to n do
            result := result*i;
end;

function permutestring(originalstring : string;
                                 whichperm : Int64) : string;
var
     numperms : int64;
     takechar : integer;
begin
        numperms := excited_n(length(originalstring)-1);
        result := '';
        repeat
              takechar := ((whichperm-1) div numperms) + 1;
              result := result + originalstring[takechar];
              Delete(originalstring,takechar,1);
              if (length(originalstring) > 1) then
              begin
                  whichperm := ((whichperm-1) mod numperms)+1;
                  numperms := numperms div (length(originalstring));
              end;
         until (length(originalstring) = 1);
         result := result + originalstring;
end;
0
Cloud Class® Course: Microsoft Exchange Server

The MCTS: Microsoft Exchange Server 2010 certification validates your skills in supporting the maintenance and administration of the Exchange servers in an enterprise environment. Learn everything you need to know with this course.

LischkeCommented:
sbruck,

unfortunately, you are not accepting what you got so far. We gave you several solutions but you came up with more and more new requirements. Perhaps you should pick and accept one solution and work out the rest you need yourself...

Ciao, Mike
0
sburckCommented:
Mike, it's not my question, I just offered a solution.
0
LischkeCommented:
Oops, sorry sbruck. This was a  bad mistake! I couldn't find the question (there are soooo many) so I just wrote my comment without lookup. Sorry again!

Ciao, Mike
0
sburckCommented:
Mike,  s'alright.
0
delphi3Author Commented:
Hi EE Commentors To My Question,
I do not know what part of the world you are in but as I read your notes I sse that you are restless for my approval.   FYI   I wrote the Q at 1AM my time and it is now 7AM my time. I know that some of you miss your sleep period as that is your work period. I do not miss my sleep period as it is a necessary thing.
Please forgive me for sleeping and I'll get around to checking out, grading your response.
It may be another 24 hours before I get to it. Thanks for responding.

Delphi3
0
LischkeCommented:
Well, here's it 1PM and the best time to answer questions :-)

But take your time Delphi3 and sleep as much as you need :-))

Ciao, Mike
0
delphi3Author Commented:
Hi Lischke,
Now that I am up and you are at the computer, I think that you have a piece of programming that you are taking this from, as evidenced by

procedure TMainForm.Button5Click(Sender: TObject);

Are you writing a procedure within a procedure? As evidenced by
                procedure CreateCombinations(Range: TCharRange; Depth: Cardinal;
                List: TStrings);

                var
                  Exclusion: TCharRange;

                  procedure ConstructLevel(Level: Cardinal; Item: String);

                  var
                    I: Char;  ..........

How do you declare this in the forward declaration at the start of the program and why not add the Sender: TObject to these procedures as you did in the Button5Click?

Delphi3


               



..
0
LischkeCommented:
Right Delphi3! Socalled local functions are a speciality of PASCAL. I used them only when I need to carry out an action which is only needed in one function but this function is already so complex that it is clearer to use a local routine. Another valid situation is given here as the local function is recursive. No problem to make a regular function from it, though...

The Sender parameter in the outer function is there because I have put the call to the combination function into a button click handler. You could call it from everywhere you like. Usually you don't need to declare the combination function with "forward" as it is a standalone function. Just place it so near to the implementation keyword that it can be access from all code which needs it. But if you, for whatever reason, need to declare it forward then go ahead and write:

procedure CreateCombinations(Range: TCharRange; Depth: Cardinal; List: TStrings); forward;

procedure TForm1.OnCreate(..

begin
  :
  :

etc.

procedure CreateCombinations(Range: TCharRange; Depth: Cardinal; List: TStrings);

begin
  :

etc.

Ciao, Mike


0
delphi3Author Commented:
Hi Lischke,
Is this what you intended as a response?
See my notes in the program.
Delphi3


unit Combinations2Unit1; // A MissNamed program

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls;

type
  TCharRange = set of Char;


type
  TForm1 = class(TForm)
    ListBox1: TListBox;
    Button1: TButton;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
   procedure CreateCombinations(Range: TCharRange; Depth: Cardinal;List: TStrings;Sender: TObject);
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}
procedure TForm1.Button1Click(Sender: TObject);
begin
  CreateCombinations(['A'..'Z'], 3, ListBox1.Items,Self);
end;

procedure TForm1.CreateCombinations(Range: TCharRange; Depth: Cardinal;List: TStrings;Sender:Tobject);
var
 Exclusion: TCharRange;

procedure ConstructLevel(Level: Cardinal; Item: String);
 var
  I: Char;
begin   // start of ConstructLevel
  if Level > 0 then
    begin
     for I := #65 to #68 do
      if I in (Range - Exclusion) then
       begin
         Include(Exclusion, I);
         ConstructLevel(Level - 1, I + Item);
         Exclude(Exclusion, I);
      end; //end if I
     end //end for loop
  else
  List.Add(Item);
  end;//if Level

begin // start procedure createcombinations
  List.Clear;
  if Depth > 0 then
    begin
     Exclusion := [];
     ConstructLevel(Depth, '');// recursively
   end; //end if Depth
end; //end procedure

procedure TForm1.Button2Click(Sender: TObject);
begin
Application.Terminate;
end;

end.

{Notes:
  a Permutation of 4 things taken 3 at a time is given by the
  Formula P(n,r) and for this sample is calculated by  4! divided by
 (4-3)! = 24  In the problem of letters of the alphabet:
  Q: how many 'meaningless words' can be constructed
 using 4 letters,using 3 at a time? For this problem
 there are 24 items in the output.

  a Combination of 4 things taken 3 at a time is give by the
  Formula C(n,r) and for this sample is calculated by 4! divided by
  ((4-3)!* 3!) = 4 .  In the problem of committees:
   Q: how many committees can be selected from a group of 4 people,
   3 at a time?  For this kind of problem there are only
   4 different name arrangements in the output.

  The distinction between permutation and combination is
  an important one. If order is important then a permutation
  is the desired outcome. On the other hand if order is NOT
  important then it is a combination.

   I need a program for showing Combinations as a listing
 not Permutations.  Can you help me? Thank you. Delphi3 }
0
LischkeCommented:
Okay, you made me clear a point I wasn't aware of. Sure, what I gave you was code to create permutations. While thinking about a new algo I realized that Ray's solution is what I also would use (the code in your question). What's wrong with it that you want another one?

Ciao, Mike
0
delphi3Author Commented:
Hi Lischke,
His procedure within the procedure  does not call a consistant set of variables. His list of  is unspecified.
Can that be fixed? or replaced within yours?

Delphi3
0
LischkeCommented:
Hi Delphi3,

oh well, this took me 3 hours to work out this so simple looking function. I hope this is now what you need. Next time, I'd suggest, you declare such a question as being hard (by assigning more points to it) ;-).

procedure CreateCombinations(Range, Elements: Integer; List: TStrings);

  procedure P(N, Elements: Integer; Current: array of Integer);

  var
    I, J: Integer;
    S: String;
    A: array of Integer;

  begin
    if Length(Current) = Elements then
    begin
      S := '';
      for I := 0 to High(Current) do S := S + IntToStr(Current[I]);
      List.Add(S);
    end
    else
    begin
      if Length(Current) > 0 then J := Current[High(Current)]
                             else J := 0;
      // create a new array which can be extended with one value
      SetLength(A, Length(Current) + 1);
      for I := 0 to High(Current) do A[I] := Current[I];
      for I := 1 to N - (Elements - Length(Current)) - J + 1 do
      begin
        A[High(A)] := I + J;
        P(N, Elements , A);
      end;
    end;
  end;

begin
  List.Clear;
  P(Range, Elements, []);
end;

procedure TMainForm.Button5Click(Sender: TObject);

begin
  CreateCombinations(5, 3, ListBox1.Items);
end;

The core function P takes three arguments. The first one is the upper limit of a range of integer numbers (going so from 1..N). The second parameter is the number of elements the results should comprise and the third parameter can be empty to start output with the first possible combination or any combination (or part of combination) to start output with.

Ciao, Mike
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
delphi3Author Commented:
Hi Lischke,
Nice job. I placed your answer in a program that takes your combination number  lists  and converts it to lists  of combinations using names/words.
As for making the program difficulty level as a hard one. Well, that is how prepared you were to answer. I had no idea as to how prepared you were. But I increased the points.

Have a good day.

Delphi3

My  solution is below

unit CombinationTwoUnit1;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
Dialogs,StdCtrls;

type
TForm1 = class(TForm)
    ListBox1: TListBox;
    ListBox2: TListBox;
    Button1: TButton;
    Button2: TButton;
    Edit1: TEdit;
    Edit2: TEdit;
    Label1: TLabel;
    Label2: TLabel;
    Label3: TLabel;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
     private
    procedure CreateCombinations(Range, Elements: Integer; ListBox1:TStrings;Sender:Tobject);
    procedure ReadAndTransfer(Sender: TObject);
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.Button1Click(Sender: TObject);
begin
  CreateCombinations(StrToInt(Edit1.Text),StrToInt(Edit2.Text), ListBox1.Items,Self);
  ReadAndTransfer(Self);
  end;

procedure TForm1.CreateCombinations(Range, Elements: Integer; ListBox1:TStrings;Sender:Tobject);

procedure P(N, Elements: Integer; Current: array of Integer);
var
  I, J: Integer;
  S: String;
  A: array of Integer;

begin
  if Length(Current) = Elements then
     begin
       S := '';
       for I := 0 to High(Current) do S := S + IntToStr(Current[I]);ListBox1.Add(S);
     end
     else
     begin
       if Length(Current) > 0 then J := Current[High(Current)]
       else J := 0;
  // create a new array which can be extended with one value
        SetLength(A, Length(Current) + 1);
        for I := 0 to High(Current) do
        A[I] := Current[I];
        for I := 1 to N - (Elements - Length(Current)) - J + 1 do
          begin
            A[High(A)] := I + J;
            P(N, Elements , A);
          end;
      end;
   end;

begin
  P(Range, Elements, []);
end;


procedure TForm1.ReadAndTransfer(Sender: TObject);
var
ListArra:Array[0..20] of String; // more than enough
FName:Array[0..20] of String;  //more than enough
Itm:String;
I,I1,I2,Num,C,D :Integer;
Data:Textfile;
begin
  C := ListBox1.Items.Count;
  for I := 0 to C-1 do
    ListArra[I]:= Form1.ListBox1.Items.Strings[I];
  //Reading File with names
  //List of names/words  MUST contain AT LEAST a number of elements N
  Reset(Data,'MyNameList.txt');
  Num := 0;
  Readln(Data,FName[Num]);
    while not EOF(Data) do
      begin
        Num:= Num + 1;
        Readln(Data,FName[Num]);
     end;
   CloseFile(Data);
   If StrToInt(Edit1.Text) > Num + 1 then Exit;
   For I1 := 1 to C do
   begin
       Itm:= ListArra[I1-1];
       for I2 := 1 to Length(Itm) do
         begin
          D := StrToInt(Itm[I2]);
          Form1.Listbox2.Items.Add(FName[D-1]);
         end;
      Form1.Listbox2.Items.add ('  '); //a blank separator
   end;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
 Application.Terminate;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  Edit1.clear;
  Edit1.Color:= clyellow;//Attention getting device
  Edit2.clear;
  Edit2.Color:= clyellow;
end;

end.

{ Form Viewed as Text

object Form1: TForm1
  Left = 185
  Top = 103
  Width = 474
  Height = 377
  Caption = 'Combinations To List'
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'MS Sans Serif'
  Font.Style = []
  OldCreateOrder = False
  OnCreate = FormCreate
  PixelsPerInch = 96
  TextHeight = 13
  object Label1: TLabel
    Left = 208
    Top = 56
    Width = 21
    Height = 13
    Caption = 'n := '
  end
  object Label2: TLabel
    Left = 208
    Top = 104
    Width = 18
    Height = 13
    Caption = 'r := '
  end
  object Label3: TLabel
    Left = 200
    Top = 24
    Width = 28
    Height = 13
    Caption = 'C (n,r)'
  end
  object Button1: TButton
    Left = 216
    Top = 152
    Width = 75
    Height = 25
    Caption = 'Run'
    TabOrder = 0
    OnClick = Button1Click
  end
  object Button2: TButton
    Left = 216
    Top = 192
    Width = 75
    Height = 25
    Caption = 'Close'
    TabOrder = 1
    OnClick = Button2Click
  end
  object ListBox1: TListBox
    Left = 56
    Top = 32
    Width = 129
    Height = 289
    ItemHeight = 13
    TabOrder = 2
  end
  object Edit1: TEdit
    Left = 232
    Top = 56
    Width = 49
    Height = 21
    TabOrder = 3
    Text = 'Edit1'
  end
  object Edit2: TEdit
    Left = 232
    Top = 104
    Width = 49
    Height = 21
    TabOrder = 4
    Text = 'Edit2'
  end
  object ListBox2: TListBox
    Left = 320
    Top = 32
    Width = 121
    Height = 289
    ItemHeight = 13
    TabOrder = 5
  end
end
}

0
LischkeCommented:
Yes indeed, the difficultness can be considered as function of preparedness. Honestly, I was nearly going to give up to provide a solution as I haven't done this kind of maths a few years now, but somehow I'd like to find a solution primarily to see whether I still can it :-)

Well, finally you got what you needed and that is what counts.

Ciao, Mike
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Delphi

From novice to tech pro — start learning today.