【问题标题】:Enumerate possible set values in Delphi在 Delphi 中枚举可能的设置值
【发布时间】:2010-11-04 00:06:27
【问题描述】:

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

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

我想知道使用整数循环来枚举它们:

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

这不会编译。我想知道是否有任何相当简单的方法可以从 Integer 转换为 Set(网络上的大多数问题都尝试另一种方式,从 Set 转换为 Integer),如果有,它是什么?

另一种可能性是将整数用作位域:

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

然后使用按位与测试成员资格:

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

我已经尝试过了,它确实有效,但感觉使用集合会更自然,并且更好地使用类型系统(即使我要超出上述类型系统来枚举集合)。

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

注意事项:

  1. 我知道理论上不能保证集合的整数值(尽管如果您不使用枚举编号,我怀疑它们在实践中是可行的)。
  2. 可能有四个以上的选项(是的,我知道它会呈指数增长,如果选项太多,算法可能会永远占用)。

【问题讨论】:

    标签: delphi set


    【解决方案1】:

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

    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;
    

    【讨论】:

    • 非常好,让它看起来更整洁(虽然我可能会坚持另一个只是因为它更快)。
    【解决方案2】:

    试试

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

    【讨论】:

    • 确实有效。我认为它不适用于超过 8 个成员的集合? (虽然到那时算法可能已经太慢了)。
    • 执行 sizeof(SetVar) 以了解 Delphi 如何表示特定集合。
    【解决方案3】:

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

    如果您有一个包含超过 8 个但少于 16 个可能元素的集合,则可以使用 Word(而不是整数)。

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

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

    【讨论】:

    • 问题不在于整数的大小,问题在于他试图转换为set类型(TMyOptions),而不是枚举类型。跨度>
    • Alberto:在这种情况下,设置为 byte-word-dword 类型转换当然是可能的并且是有意义的。
    【解决方案4】:

    500 - Internal Server Error 的答案可能是最简单的。

    另一种不太可能因更改选项数量而中断的方法是声明一个布尔数组,并打开/关闭它们。不过,这比使用纯整数要慢。主要优点是您不需要更改您使用的整数类型,如果您有超过 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】:

      从整数转换为集合是不可能的,但Tondrej 曾经在SetToStringStringToSet 上写了一个blog article,它在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】:

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

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

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

        几个月前我遇到了同样的问题,得出的结论是您无法在 Delphi 中枚举集合的内容(至少在 Delphi 7 中),因为该语言没有在集合上定义此类操作。

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

        【讨论】:

        • 查看接受的答案。使用字节而不是整数确实有效。
        • erm... 您可以枚举集合的内容。这只是违反直觉的。即对于 I := Low(Enum) to high(Enum) do /// if I in Set then.
        • 或者,从Delphi 2005开始,可以直接枚举内容:for el in s do ...
        猜你喜欢
        • 2019-07-08
        • 2020-02-27
        • 2011-07-19
        • 2011-02-23
        • 2011-11-14
        • 1970-01-01
        • 1970-01-01
        • 2013-05-17
        • 1970-01-01
        相关资源
        最近更新 更多