在Delphi中枚举可能的集合值

在Delphi中枚举可能的集合值,delphi,set,Delphi,Set,我在Delphi中有一个包含许多不同选项的计算算法,我需要尝试每个选项的组合以找到最佳解决方案 TMyOption = (option1, option2, option3, option4); TMyOptions = set of TMyOption; 我想知道如何使用整数循环来枚举它们: for EnumerationInteger := 0 to 15 do begin Options := TMyOptions(EnumerationInteger); end; 这是不可编

我在Delphi中有一个包含许多不同选项的计算算法,我需要尝试每个选项的组合以找到最佳解决方案

TMyOption = (option1, option2, option3, option4);
TMyOptions = set of TMyOption;
我想知道如何使用整数循环来枚举它们:

for EnumerationInteger := 0 to 15 do begin
    Options := TMyOptions(EnumerationInteger);
end;
这是不可编译的。我想知道的是,是否有任何相当简单的方法可以从整数转换为整数(网络上的大多数问题都试图从另一个方向,从整数转换为整数),如果有,是什么方法

另一种可能是将整数用作位字段:

C_Option1 = 1;
C_Option2 = 2;
C_Option3 = 4;
C_Option4 = 8;
然后使用按位and测试成员资格:

if (Options and C_Option2) > 0 then begin
    ...
end;
我已经尝试过这个方法,它是有效的,但感觉使用集合会更自然,并且更好地使用类型系统(尽管我要在所述类型系统之外枚举集合)

是否有比枚举基础整数表示更好/更安全的方法来枚举所有可能的集合组合

注:

  • 我知道在理论上不能保证一个集合的整数值(尽管我怀疑如果你不使用枚举编号,它们在实践中是可以保证的)
  • 可能有四个以上的选项(是的,我知道它是指数增长的,如果有太多的选项,算法可能永远需要)
  • 试一试


    您的代码无法编译,因为您的枚举(TMyOption)的值小于8,并且Delphi使用集合的最小可能大小(以字节为单位)。因此,字节变量将适用于您

    如果您有一个包含8个以上但少于16个可能元素的集合,则一个字将起作用(而不是整数)

    对于大于16但小于32的DWord变量和类型转换


    对于超过32个可能的元素,我认为更好的方法是使用字节数组或类似的东西。

    问题是您试图强制转换到集合类型而不是枚举类型。您可以在integer和enumerated之间进行强制转换,因为两者都是序号类型,但您不能强制转换为集合,因为它们使用位字段,正如您已经指出的那样。如果您使用:

    for EnumerationInteger := 0 to 15 do begin
      Option := TMyOption(EnumerationInteger);
    end;
    
    虽然这不是你想要的,但它会起作用

    几个月前我也遇到过同样的问题,我得出结论,在Delphi中不能枚举集合的内容(至少在Delphi7中是这样),因为该语言没有对集合定义这样的操作


    编辑:似乎您甚至可以在D7中查看此答案的答案。

    500-内部服务器错误的答案可能是最简单的

    另一种不太可能因选项数量的变化而中断的方法是声明一个布尔值数组,并打开/关闭它们。但这比使用纯整数要慢。主要的优点是,您不需要更改所使用的整数类型,如果有32个以上的选项,您可以使用它

    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;
    
    程序剂量测量
    var BoolFlags:布尔值的数组[Topion];
    I:托吡酯;
    函数GetNextFlagSet(var Bools:Boolean数组):Boolean;
    var idx,I:整数;
    开始
    idx:=0;
    
    虽然Bools[idx]和(idx从整数到集合的转换是不可能的,但一旦在
    SetToString
    StringToSet
    上编写了一个函数,该函数公开了在
    SetOrdValue
    方法中需要的内容:

    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;
    
    然后,您的代码将变成:

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

    --jeroen

    我知道这个问题很老了,但这是我的偏好,因为它对我来说既简单又自然:

    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;
    

    这确实有效。我假设它不适用于包含8个以上成员的集合(虽然到那时算法可能已经太慢了)。请执行sizeof(SetVar)以了解特定集合是如何用Delphi表示的。问题不是整数的大小,而是他试图转换为集合类型(TMyOptions),而不是枚举类型。Alberto:在这种情况下,设置为字节的单词dword类型转换当然是可能的,并且是有意义的。请参阅公认的答案。使用字节而不是整数确实有效。呃…您可以枚举集的内容。这只是违反直觉。例如,对于i:=低(枚举)到高(枚举)do///如果我当时在集合中。或者,从Delphi 2005开始,您可以直接枚举内容:
    for el in s do…
    非常好,使它看起来更整洁(尽管我可能会坚持使用另一个,因为它更快)。
    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;