Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Iterate through items in an enumeration in Delphi

Tags:

I want to iterate through the items in an enumeration.

I'd like to be able to say something like this:

type   TWeekdays = (wdMonday, wdTuesday, wdWednesday, wdThursday, wdFriday);  ... elementCount := GetElementCount(TypeInfo(TWeekDays));  for i := 0 to elementCount - 1 do begin   ShowMessage(GetEnumName(TypeInfo(TWeekdays),i)); end; 

The closest I've been able to come is this:

function MaxEnum(EnumInfo: PTypeInfo): integer; const   c_MaxInt = 9999999; var   i: integer;   s: string; begin   //get # of enum elements by looping thru the names   //until we get to the end.   for i := 0 to c_MaxInt do begin     s := Trim(GetEnumName(EnumInfo,i));     if 0 = Length(s) then begin       Result := i-1;       Break;     end;   end; end; 

Which I use like this:

procedure TForm1.BitBtn1Click(Sender: TObject); var   i, nMax: integer; begin   ListBox1.Clear;   nMax := MaxEnum(TypeInfo(TWeekdays));   for i := 0 to nMax do begin     ListBox1.Items.Add(GetEnumName(TypeInfo(TWeekdays),i));   end; end; 

That works well, except the list I get looks like this (notice the last two items):

wdMonday wdTuesday wdWednesday wdThursday wdFriday Unit1 '@'#0'ôÑE'#0#0#0#0#0#0#0#0#0#0#0#0#0  <more garbage characters> 

The two items at the end are obviously not what I want.

Is there a better way to iterate through the elements of an enumerated type?

If not, then is it safe to assume that there will always be exactly two extra items using my current method? Obviously one is the Unit name... but what is the "@" symbol doing? Is it really garbage, or is it more type information?

I'm using Delphi 2007. Thanks for any insights.

like image 582
JosephStyons Avatar asked Oct 21 '09 12:10

JosephStyons


People also ask

How do you iterate through an enumeration?

To iterate through an enumeration, you can move it into an array using the GetValues method. You could also iterate through an enumeration using a For... Each statement, using the GetNames or GetValues method to extract the string or numeric value.

Can I iterate over an enum?

Enums don't have methods for iteration, like forEach() or iterator(). Instead, we can use the array of the Enum values returned by the values() method.

Can you iterate through an enum in C?

you can iterate the elements like: for(int i=Bar; i<=Last; i++) { ... } Note that this exposes the really-just-an-int nature of a C enum. In particular, you can see that a C enum doesn't really provide type safety, as you can use an int in place of an enum value and vice versa.

Can you iterate through an enum Javascript?

Use the Object. keys() or Object. values() methods to get an array of the enum's keys or values.


2 Answers

Simple:

type   TWeekdays = (wdMonday, wdTuesday, wdWednesday, wdThursday, wdFriday);  procedure Test; var   el: TWeekdays; begin   for el := Low(TWeekdays) to High(TWeekdays) do     ; // end; 
like image 135
gabr Avatar answered Sep 20 '22 00:09

gabr


It is quite more complex than that, when used special enumerations... let's see a really 100% working solution for a complex enumerated definition:

type     TmyEnumType=(myEnumTypeA=5,myEnumTypeB=2,myEnumTypeC=9); const      myEnumTypeOrder:Array[1..3] of TmyEnumType=(myEnumTypeA,myEnumTypeB,myEnumTypeC); procedure TForm1.Button1Click(Sender: TObject); var    myEnumTypeVariable:TmyEnumType; begin      myEnumTypeVariable:=Low(TmyEnumType);      for myEnumTypeVariable in myEnumTypeOrder      do begin              ShowMessage(IntToStr(Ord(myEnumTypeVariable))); // Sample code to show enum integer value              // Extra code you neede         end; end; // This code shows three messages in this secuence: 5, 2, 9 //    Correct number of elements and in the correct order 

Notes:

  • Not all enumerated definitions must start with 0 and be contiguous, can be defined as on the sample
  • See how the type has been defined (not sorted, not contiguous, etc...)
  • See how it has been added a constant array with the correct order of the elements
  • Must iterate on such array since order is lost and Succ and Pred do not work properly on that kind of enumerations

Why it has been done like that?:

  • Enumerated order must be conserved and it is not contiguous
  • Delphi when on that sample creates type TmyEnumType assign to it (9-2+1=8) elemments (from lower one (2) to higher one (9), so valid values for such type are from ordinal 2 to ordinal 9
  • Delphi Succ and Pred functions only increase and decrese by one, do not check for non-contiguous way of defining it, so assign values that are out of scope, and also loose the order of definition

The Trick:

  • Declare a contiguous constant array with elements in the correct order
  • Loop on that constant array

If you try this other (logical human way of thinking) it will not work (no matter if use for loop, while loop, repeat until, etc):

type     TmyEnumType=(myEnumTypeA=5,myEnumTypeB=2,myEnumTypeC=9); procedure TForm1.Button1Click(Sender: TObject); var    myEnumTypeVariable:TmyEnumType; begin      for myEnumTypeVariable:=Low(TmyEnumType) to High(TmyEnumType);      do begin              ShowMessage(IntToStr(Ord(myEnumTypeVariable))); // Sample code to show enum integer value              // Extra code you neede         end; end; // This code shows eight messages in this secuence: 2, 3, 4, 5, 6, 7, 8, 9 //    Inorrect number of elements and in order is lost 

That is what i have tested by my own on Turbo Delphi 2006.

like image 33
anonymous Avatar answered Sep 24 '22 00:09

anonymous