?
Solved

Sets

Posted on 2003-03-06
30
Medium Priority
?
179 Views
Last Modified: 2010-04-04
type
  TBedienpunt = (Start, Groente, Vlees, Brood, Sigaren, Kassa);

  TBedienpunten = set of TBedienPunt;

var
  Bezoek: TBedienpunten;

...
Bezoek := [Start, Vlees, Sigaren];
...

How can i get a random TBedienpunt out of the set 'Bezoek'???
0
Comment
Question by:remcotolsma
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 11
  • 8
  • 5
  • +3
30 Comments
 
LVL 27

Expert Comment

by:kretzschmar
ID: 8078957
>How can i get a random TBedienpunt out of the set 'Bezoek'???

? how should a random set shown ?

can you show some examples?
0
 

Author Comment

by:remcotolsma
ID: 8078991
type
 TBedienpunt = (Start, Groente, Vlees, Brood, Sigaren, Kassa);

 TBedienpunten = set of TBedienPunt;

...
var
 Bezoek: TBedienpunten;
...

...
Bezoek := [Start, Vlees, Sigaren];
...

I want to pick one item (TBedienpunt) out of Bezoek (set of TBedienpunt).
For example in an function:

function RandomBezoek(Bezoek: TBedienpunten): TBedienpunt;
begin
  ...
end;

-------------------------

RandomBezoek(Bezoek)
gives for example as result 'Vlees'!
0
 
LVL 2

Expert Comment

by:Kalroth
ID: 8079184
When delphi makes set enums, it uses different datatypes to store them in.
A set of 1 to 8 items is a Byte, 9 to 16 is a Word, 17 to 32 is a LongWord.

Knowing this you can just typecast it to either type and do something like the following:

(** CODE START **)

type
  TBedienpunt = (Start, Groente, Vlees, Brood, Sigaren, Kassa);
  TBedienpunten = set of TBedienPunt;

function GetRandomValue(AValueSet: TBedienpunten): TBedienpunt;
begin
  if AValueSet = [] then
  begin
    ShowMessage('Set must contain at least one value.');
    result := Start;
    Exit;
  end else begin
    result := TBedienpunt(Random(63));
    // 63  = 6 enums in the set
    // 127 = 7 enums in the set
    // 255 = 8 enums in the set
    // 511 = 9 enums in the set
    while (result in AValueSet) = False do
      result := TBedienpunt(Random(63));
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  val : TBedienpunt;
  valset : TBedienpunten;
begin
  Randomize;
  valset := [Start,Groente,Sigaren];
  val := GetRandomValue(valset);
  case val of
    Start   : memo1.lines.add('Start');
    Groente : memo1.lines.add('Groente');
    Vlees   : memo1.lines.add('Vlees');
    Brood   : memo1.lines.add('Brood');
    Sigaren : memo1.lines.add('Sigaren');
    Kassa   : memo1.lines.add('Kassa');
  end;
end;

(** CODE END **)

Button1Click() is just some sample code to test it.

Yes, I'm aware it probably could be optimized, but this (should) work just fine, even if it isn't the fastest code.
0
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 2

Expert Comment

by:Kalroth
ID: 8079210
Ooops, the above code minor correction, sorry.

It works, but I mixed the "set of" and the actual value up.
You don't need to do Random(63), just use the amount of values possible. So in the above example, it should be:

function GetRandomValue(AValueSet: TBedienpunten): TBedienpunt;
begin
  if AValueSet = [] then
  begin
    ShowMessage('Set must contain at least one value.');
    result := Start;
    Exit;
  end else begin
    result := TBedienpunt(Random(6));
    while (result in AValueSet) = False do
      result := TBedienpunt(Random(6));
  end;
end;

Sorry for the mixup, this should be much faster.
0
 
LVL 27

Expert Comment

by:kretzschmar
ID: 8079293
well, my version,


unit Unit1;

interface

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

type
  TForm1 = class(TForm)
    CheckBox1: TCheckBox;
    CheckBox2: TCheckBox;
    CheckBox3: TCheckBox;
    CheckBox4: TCheckBox;
    CheckBox5: TCheckBox;
    CheckBox6: TCheckBox;
    Button1: TButton;
    CheckBox7: TCheckBox;
    CheckBox8: TCheckBox;
    CheckBox9: TCheckBox;
    CheckBox10: TCheckBox;
    CheckBox11: TCheckBox;
    CheckBox12: TCheckBox;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

  TBedienpunt = (Start, Groente, Vlees, Brood, Sigaren, Kassa);
  TBedienpunten = set of TBedienPunt;



var
  Form1: TForm1;
  Bezoek: TBedienpunten;
  Bezoekitem:TBedienpunt;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
  randomize;
end;


//sets a random set
function get_random_set : TBedienpunten;
var i : TBedienpunt;
begin
  result := [];
  for i := low(TBedienpunt) to high(TBedienpunt) do
    if (random(10) mod 2) = 1 then
      result := result + [i];
end;

//gets a random item
function get_random_item(ASet : TBedienpunten) : TBedienpunt;
var
  v : array [TBedienpunt] of Boolean;
  i : TBedienpunt;
begin
  if ASet = [] then
    raise exception.Create('Cannot do this on an empty set');
  //collect
  for i := low(TBedienpunt) to high(TBedienpunt) do
  begin
    v[i] := false;
    if (i in aset) then
      v[i] := true;
  end;
  //get a random
  repeat
    result := TBedienpunt(random(integer(high(TBedienpunt))+1));
  until v[result]
end;


procedure TForm1.Button1Click(Sender: TObject);
begin
  bezoek := get_random_set;

  //output
  checkbox1.Checked := Start   in bezoek;
  checkbox2.Checked := Groente in bezoek;
  checkbox3.Checked := Vlees   in bezoek;
  checkbox4.Checked := Brood   in bezoek;
  checkbox5.Checked := Sigaren in bezoek;
  checkbox6.Checked := Kassa   in bezoek;

  bezoekitem := get_random_item(bezoek);
  //output
  checkbox7.Checked := bezoekitem = Start;
  checkbox8.Checked := bezoekitem = Groente;
  checkbox9.Checked := bezoekitem = Vlees;
  checkbox10.Checked := bezoekitem = Brood;
  checkbox11.Checked := bezoekitem = Sigaren;
  checkbox12.Checked := bezoekitem = Kassa;


end;

end.

meikl ;-)
0
 
LVL 1

Expert Comment

by:krukmat
ID: 8079294
try with this function
function RandomBezoek(var Bezoek: TBedienpunten): TBedienpunt;
var
  posBezoek:word;
begin
  randomize;
  posBezoek:=random(6);
  result:=TBedienpunt(posBezoek);
  while not(result in Bezoek) do
  begin
    posBezoek:=random(6); //6 elements in TBedienpunt
    result:=TBedienpunt(posBezoek);
  end;
  Bezoek:= Bezoek - [result];
end;
0
 
LVL 27

Expert Comment

by:kretzschmar
ID: 8079347
well, based on Kalroth suggestion
a replacement (sometimes i think too complicated :-))

//gets a random item
function get_random_item(ASet : TBedienpunten) : TBedienpunt;
begin
  if ASet = [] then
    raise exception.Create('Cannot do this on an empty set');
  //get a random
  repeat
    result := TBedienpunt(random(integer(high(TBedienpunt))+1));
  until result in aset;
end;

meikl ;-)
0
 
LVL 2

Expert Comment

by:j42
ID: 8080154
My suggestion to solution of kretzschmar:

repeat
   result := TBedienpunt(random(integer(high(TBedienpunt))+1));
until result in aset;

--->

result := TBedienpunt(random(integer(high(TBedienpunt))+1));
while not (result in aset) do
  result := TBedienpunt(integer(succ(result)) mod (integer(High(TBedienpunt)) + 1));
0
 
LVL 27

Expert Comment

by:kretzschmar
ID: 8080217
:-))

i know that a while is faster than repeat-until,
but on this small set it will not significant,
therefore i like it more readable,
but thanks for your suggestion, j42

anyway, what should this be
  result := TBedienpunt(integer(succ(result)) mod (integer(High(TBedienpunt)) + 1));

meikl ;-)
0
 
LVL 2

Expert Comment

by:j42
ID: 8080281
Hi,

you call Random() in the loop, I call it just once then skip to the next item in the set. The mod is just to avoid a 'Out of bounds' since Succ() does not care about the upper limit of TBedienpunt.
In some cases your loop will never finish (very small probability)...
0
 
LVL 27

Expert Comment

by:kretzschmar
ID: 8080359
very small probability, yep,
never had this, but yes, good idea, j42
0
 
LVL 1

Expert Comment

by:SimesA
ID: 8110472
But j42's mod means the result is no longer random.

TBedienpunt = (Start, Groente, Vlees, Brood, Sigaren, Kassa);

Consider a call with the set [Brood, Sigaren, Kassa] - A random algorithm would return each with a probability of 1/3.

But j42's would be more likely to return Brood than the other two. Why? let's see...

The initial assignment of result
   result := TBedienpunt(random(integer(high(TBedienpunt))+1));
would be a random choice of the 6 *possible* elements in the set, each with 1/6 probability. But since the first three elements aren't actually in the allowed result, the code would return the next element that was present, i.e. Brood. So the probabilities are now:
  Brood:   4/6
  Sigaren: 1/6
  Kassa:   1/6

kretzschmar's solution was better!
0
 
LVL 1

Expert Comment

by:SimesA
ID: 8110504
Some code to illustrate the problem...


type
  TBedienpunt = (Start, Groente, Vlees, Brood, Sigaren, Kassa);
  TBedienpunten = set of TBedienPunt;

function kretzschmar(const ASet: TBedienpunten): TBedienpunt;
begin
  if ASet = [] then
    raise exception.Create('Cannot do this on an empty set');
  repeat
    result := TBedienpunt(random(integer(high(TBedienpunt)) + 1));
  until result in aset;
end;

function J42(const ASet: TBedienpunten): TBedienpunt;
begin
  if ASet = [] then
    raise exception.Create('Cannot do this on an empty set');
  result := TBedienpunt(random(integer(high(TBedienpunt)) + 1));
  while not (result in aset) do
    result := TBedienpunt(integer(succ(result)) mod (integer(High(TBedienpunt)) + 1));
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  counts: array[TBedienpunt] of integer;
  i: TBedienpunt;
  x: integer;
  str: string;
begin
  button1.Enabled := false;
  try
    for i := low(TBedienpunt) to high(TBedienpunt) do
      counts[i] := 0;
    for x := 1 to 1000 do begin
      i := kretzschmar([Brood, Sigaren, Kassa]);
      inc(counts[i]);
    end;

    str := '';
    for i := low(TBedienpunt) to high(TBedienpunt) do
      str := str + ', ' + IntToStr(counts[i]);
    label1.caption := str;


   
    for i := low(TBedienpunt) to high(TBedienpunt) do
      counts[i] := 0;
    for x := 1 to 1000 do begin
      i := j42([Brood, Sigaren, Kassa]);
      inc(counts[i]);
    end;

    str := '';
    for i := low(TBedienpunt) to high(TBedienpunt) do
      str := str + ', ' + IntToStr(counts[i]);
    label2.caption := str;

  finally
    button1.Enabled := true;
  end;
end;

0
 
LVL 27

Expert Comment

by:kretzschmar
ID: 8110977
hmm, i see, good work, SimesA
0
 
LVL 2

Expert Comment

by:j42
ID: 8130405
Darn! I did not think anyone will notice that...

:-)
J
0
 
LVL 2

Expert Comment

by:j42
ID: 8130418
Should be???
I did not think anyone would notice that...
(Non native english speaker)
0
 
LVL 27

Expert Comment

by:kretzschmar
ID: 8130737
whats your native language, j42?
0
 
LVL 2

Expert Comment

by:j42
ID: 8134897
Hi all,
did anybody say I would not do my homework?



type
 TBedienpunt = (Start, Groente, Vlees, Brood, Sigaren, Kassa);
 TBedienpunten = set of TBedienPunt;

var
  Bezoek: TBedienpunten = [Start, Vlees, Sigaren];

function GetStuff(const bedienpunten: TBedienpunten): TBedienpunt;
var
  tmpArr: array of TBedienpunt;
  arrLen: integer;
  idx: TBedienpunt;
begin
  if ([] = bedienpunten) then Exit;

  arrLen := 0;
  for idx := Low(idx) to High(idx) do
  begin
    if (idx in bedienpunten) then
    begin
      Inc(arrLen);
      SetLength(tmpArr, arrLen);
      tmpArr[arrLen - 1] := idx;
    end;
  end;
  Result := tmpArr[Random(arrLen)];
end;



I know this peace of code is painfully slow due to the dynamic array. However I want to point out that the algorithm does not make use of any ugly typecast!
To algorithm of Kretschmar:
The probability to finish the function after n loops is (1 - (1-p)^n) where p is the probability to get a match. Thus the number of loops for a 100% probability to leave the function is n = ln(0) / ln(1 - p) = infinite. :-)



Greetings from Germany
J
0
 
LVL 2

Expert Comment

by:j42
ID: 8134910
kretzschmar,
pls apologize spelling your name wrong.
0
 
LVL 2

Expert Comment

by:j42
ID: 8134917
Should be:
The probability to finish the function after n loops is (1 - (1-p)^n) where p is the probability _not_ to get a match
0
 
LVL 1

Expert Comment

by:SimesA
ID: 8135073
Purely out of interest, can you give us a suitable RandSeed and an example set so that kretzschmar's routine never returns?

Or even what's the largest number of iterations it takes to return an answer for a given input?
0
 
LVL 2

Expert Comment

by:j42
ID: 8135188
Hi SimesA,

Brain cramp, should be:
The probability to finish the function after n loops is (1 - (1-p)^n) where p _is_ the probability to get a match

I will try to explain a little bit (althoug it is not easy for me to do this in english).
> an example set so that kretzschmar's routine never returns
That is a wrong question. Unless your set does not contain all the items (p = 100%) you can not be sure to leave the loop.

Example:
Bezoek := [Start, Groente, Vlees, Brood, Sigaren];   // Kassa missing

The propability not to leave the function after on call to Random() is 1/6 (as you said). If you call Random() a second time the probability gets less (1/36 = 1/6^2) but still it not equal zero. As you can see it is possible to loop for hours and hit Kassa every time (Ok, it is not very likely, I admitt).

This is just fun if we have got sets like the above. But think of types like
type
  TPathological = (t000001, t000002, ... t999999);
  TSetPth = [t000004, t000011];
You would be better implementing an hourglass ;-)



Regards
J
0
 
LVL 27

Expert Comment

by:kretzschmar
ID: 8135192
>Purely out of interest, can you give us a suitable
>RandSeed and an example set so that kretzschmar's routine
>never returns?

may not possible (set too small,
if the set would be contain 10000 and 2 were selected,
than it may take time because of much tries to get
rondomly one if this 2 of 10000 randomly, but after
a random of tries it will hit)

>Or even what's the largest number of iterations it takes
>to return an answer for a given input?

would be random :-)))

i thought also of filling an array,
with the only selected set-entries, j42,
but discarded it, because of the small set,
but for large sets its better to do so.

meikl ;-)
0
 
LVL 1

Expert Comment

by:SimesA
ID: 8135201
kretzschmar: That's really the point I was making. For the example given, your routine will always return a value.
0
 
LVL 2

Expert Comment

by:j42
ID: 8135208
remcotolsma,

what the hell is a Bedienpunt, a Start, Groente, Vlees, Brood, Sigaren, Kassa and a Bezoek?

Regards
0
 
LVL 2

Accepted Solution

by:
j42 earned 270 total points
ID: 8135222
Hi all,

thanks for the discussion. I am out of the office now. Have a nice weekend.

Regards
J
0
 

Author Comment

by:remcotolsma
ID: 8138312
Hi all,

Thx voor the tips...

-------------------------------------------------
J42

Haha jah euh...

It's dutch... that explains a lot i think. :)...
I'm working on a supermarket simulation!

Start = Start :P
Groente = Vegetables
Vlees = Meat
Brood = Bread
Kassa = Check-out

:)..

Get it?
-------------------------------------------------
0
 
LVL 1

Expert Comment

by:SimesA
ID: 8140472
remcotolsma: I'm happy you got an answer you like, but I'm curious as to why you thought J42's answer was the correct one.

kretzschmar: It doesn't look like you're short of points anyway!
0
 

Author Comment

by:remcotolsma
ID: 8142153
Well... honestly i still don't have a answer i like. The codes isn't very fast... not the fastest ;).
Everytime a customer is going to a next 'Bedienpunt' I used one the codes you gave me. The program picks a random 'next 'Bedienpunt'. The customer is going to that 'Bedienpunt'. But the program also removes this 'Bedienpunt' from his shopping list (Bezoek).

If a customer is created he gets a shopping list...

Bezoek := [Start, Groente, Bakproducten, Frisdranken, Biologisch, Broodbeleg, Broodvervangers, Chips, Drogisterij, Fruit, Huishoudelijk, Kaas, Thee, Kruiden, Koek, Speciaal, Vegetarisch, Wijn, Zuivel];

So this list will become smaller... if the customer is almost ready with shopping then Bezoek can become somethin like this:

Bezoek = [Wijn];

then the code still picks a random 'Bedienpunt' from TBediepunt. And TBedienPunt isn't very little anymore:

TBedienPunt = (Start, Groente, Baby, Bakproducten, Bier, Frisdranken, Biologisch, Broodbeleg, Broodvervangers, Chips, Diepvries, Dierenverzorging, Drogisterij, Fruit, Huishoudelijk, Kaas, Koffie, Thee, Kruiden, Maaltijdmixen, Soepen, Rookwaren, Sauzen, Snoep, Koek, Speciaal, Vegetarisch, Vlees, Salades, Vis, Wijn, Zuivel, Kassa);

It cost al lot of time before the program picks random 'Wijn' from TBediepunt. I think it would be much more efficient if the program picks the random Bedienpunt from the set Bezoek. And not from the ordinal type TBedienPunt!
Don't forget that if the simulations is running the number of customers could become very large.

The answers you gave are working, but it still could be optimized.
0
 
LVL 2

Expert Comment

by:j42
ID: 8142970
I would like to share the reward:

Kalroth
http://www.experts-exchange.com/Programming/Programming_Languages/Delphi/Q_20551900.html
krukmat
http://www.experts-exchange.com/Programming/Programming_Languages/Delphi/Q_20551901.html
SimesA
http://www.experts-exchange.com/Programming/Programming_Languages/Delphi/Q_20551902.html
kretzschmar
http://www.experts-exchange.com/Programming/Programming_Languages/Delphi/Q_20551903.html



kretzschmar,
> but after a random of tries it will hit
I think you are wrong and everybody familiar with statistics will tell you so.

SimesA,
> Or even what's the largest number of iterations it takes to return
The question is:
How many iterations are neccessary to return with a certain probability
Example:
  10: p = 70%
  50: p = 90%
5000: p = 99%
but you can never ever in your life get a probability of 100%. Of course it is possible to return after the first 'iteration'.

remcotolsma,
> The answers you gave are working, but it still could be optimized
I guess that is the purpose of EE :-)



Best of luck
J42
0

Featured Post

Free Tool: SSL Checker

Scans your site and returns information about your SSL implementation and certificate. Helpful for debugging and validating your SSL configuration.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

In this tutorial I will show you how to use the Windows Speech API in Delphi. I will only cover basic functions such as text to speech and controlling the speed of the speech. SAPI Installation First you need to install the SAPI type library, th…
Introduction I have seen many questions in this Delphi topic area where queries in threads are needed or suggested. I know bumped into a similar need. This article will address some of the concepts when dealing with a multithreaded delphi database…
Michael from AdRem Software explains how to view the most utilized and worst performing nodes in your network, by accessing the Top Charts view in NetCrunch network monitor (https://www.adremsoft.com/). Top Charts is a view in which you can set seve…
Sometimes it takes a new vantage point, apart from our everyday security practices, to truly see our Active Directory (AD) vulnerabilities. We get used to implementing the same techniques and checking the same areas for a breach. This pattern can re…
Suggested Courses
Course of the Month10 days, 16 hours left to enroll

770 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question