代码之家  ›  专栏  ›  技术社区  ›  Jonathan Morgan

在Delphi中枚举可能的设置值

  •  6
  • Jonathan Morgan  · 技术社区  · 16 年前

    我在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;
    

    然后按位和测试成员资格:

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

    有没有比枚举底层整数表示法更好/更安全的方法来枚举所有可能的集合组合?

    笔记:

    1. 可能有四个以上的选项(是的,我知道它呈指数增长,如果有太多的选项,算法可能会永远采用)。
    6 回复  |  直到 16 年前
        1
  •  4
  •   500 - Internal Server Error    16 年前

    尝试

    var EnumerationByte: Byte;
    ...
    for EnumerationByte := 0 to 15 do begin
        Options := TMyOptions(EnumerationByte);
    end;
    
        2
  •  6
  •   Hasan S    16 年前

    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;
    
        3
  •  2
  •   jachguate    16 年前

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

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

        4
  •  0
  •   Ken Bourassa    16 年前

    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;
    
        5
  •  0
  •   Community Mohan Dere    9 年前

    Tondrej 曾经写过 blog article 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;
    

        6
  •  0
  •   Alberto Martinez    16 年前

    问题是您试图强制转换为set类型而不是枚举类型。您可以在整数和枚举之间进行强制转换,因为这两种类型都是序数类型,但您不能强制转换到集合,因为它们使用您已经注意到的位字段。如果您使用:

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

    它会起作用的,虽然不是你想要的。

    编辑