List possible values ​​in Delphi

I have a Delphi calculation algorithm with many different options, and I need to try every combination of options to find the best solution.

TMyOption = (option1, option2, option3, option4); TMyOptions = set of TMyOption; 

I wondered about using an Integer loop to list them:

 for EnumerationInteger := 0 to 15 do begin Options := TMyOptions(EnumerationInteger); end; 

This does not compile. I was wondering if there was any pretty simple way to convert from Integer to Set (most questions on the Internet try to go the other way, from Set to Integer), and if so, what is it?

Another possibility is to simply use Integer as a bit field:

 C_Option1 = 1; C_Option2 = 2; C_Option3 = 4; C_Option4 = 8; 

and then check the membership bit by bit and:

 if (Options and C_Option2) > 0 then begin ... end; 

I tried this and it works, but it seems that working with sets will be more natural and it is better to use a type system (even if I go beyond the specified type system to enumerate sets).

Is there a better / safer way to list all the possible combinations of combinations than listing the main integer representation?

Notes:

  • I know that the integer values ​​of a set are not guaranteed in theory (although I suspect that they are in practice if you are not playing with enumeration numbering).
  • There may be more than four options (yes, I know that it grows exponentially, and if there are too many options, the algorithm can last forever).
+6
set delphi
source share
6 answers

Try

 var EnumerationByte: Byte; ... for EnumerationByte := 0 to 15 do begin Options := TMyOptions(EnumerationByte); end; 
+4
source share

I know this question is quite old, but this is my preference as it is simple and natural for me:

 function NumericToMyOptions(n: integer): TMyOptions; var Op: TMyOption; begin Result:= []; for Op:= Low(TMyOption) to High(TMyOption) do if n and (1 shl ord(Op)) > 0 then Include(Result, Op); end; 
+6
source share

Your code does not compile because your enumeration (TMyOption) has less than 8 values, and Delphi uses the smallest possible size (in bytes) for sets. This way a byte variable will work for you.

If you have a collection of more than 8, but less than 16 possible elements, Word will work (and not an integer).

For more than 16, but less than 32 variables are DWord and typecast.

For over 32 possible elements, I think the best approach is to use an array of bytes or something like that.

+2
source share

The problem is that you are trying to apply to a set type, not an enumerated type. You can distinguish an integer and enumerate because both are ordinal types, but you cannot use them in a set because they use bitfiles, as you already noted. If you use:

 for EnumerationInteger := 0 to 15 do begin Option := TMyOption(EnumerationInteger); end; 

it will work, although this is not what you want.

I had the same problem a few months ago and came to the conclusion that you cannot list the contents of a set in Delphi (at least in Delphi 7), because the language does not define such an operation in a set.

Change It seems that you can even see the comments on this answer in D7.

0
source share

500 - The internal response to a server error is probably the easiest.

Another approach, which is less likely to be violated with a change in the number of options, would be to declare an array of logical ones and enable / disable them. This is slower than working with pure integers. The main advantage, you will not need to change the type of integer that you use, and you can use it if you have more than 32 options.

 procedure DoSomething var BoolFlags : Array[TOption] of Boolean; I: TOption; function GetNextFlagSet(var Bools : Array of Boolean) : Boolean; var idx, I : Integer; begin idx := 0; while Bools[idx] and (idx <= High(Bools)) do Inc(idx); Result := idx <= High(Bools); if Result then for I := 0 to idx do Bools[I] := not Bools[I]; end; begin for I := Low(BoolFlags) to High(BoolFlags) do BoolFlags[i] := False; repeat if BoolFlags[Option1] then [...] until not GetNextFlagSet(BoolFlags); end; 
0
source share

Separating from integers into a set is not possible, but Tondrej wrote a blog article on SetToString and StringToSet that provides what you want in the SetOrdValue method:

 uses TypInfo; procedure SetOrdValue(Info: PTypeInfo; var SetParam; Value: Integer); begin case GetTypeData(Info)^.OrdType of otSByte, otUByte: Byte(SetParam) := Value; otSWord, otUWord: Word(SetParam) := Value; otSLong, otULong: Integer(SetParam) := Value; end; end; 

Then your code will be as follows:

 for EnumerationInteger := 0 to 15 do begin SetOrdValue(TypeInfo(TMyOptions), Options, EnumerationInteger); end; 

- Jeroen

0
source share

All Articles