Delphi中枚举可能的设定值
我在 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;
我已经尝试过这个,它有效,但感觉使用集合会更自然并且更好地使用类型系统(即使我要超出上述类型系统来枚举集合)。
有没有比枚举底层整数表示更好/更安全的方法来枚举所有可能的集合组合?
注意:
- 我知道理论上不能保证集合的整数值(尽管我怀疑如果您不使用枚举编号,它们在实践中就会得到保证)。
- 可能有四个以上的选项(是的,我知道它呈指数级增长,如果选项太多,算法可能会永远持续下去)。
I have a calculation algorithm in Delphi with a number of different options, and I need to try every combination of options to find an optimal solution.
TMyOption = (option1, option2, option3, option4);
TMyOptions = set of TMyOption;
I wondered about using an Integer loop to enumerate them:
for EnumerationInteger := 0 to 15 do begin
Options := TMyOptions(EnumerationInteger);
end;
This does not compile. What I was wondering was if there was any fairly simple method to convert from Integer to Set (most questions on the Web try to go the other way, from Set to Integer), and if so what is it?
Another possibility is to just use the Integer as a bit-field:
C_Option1 = 1;
C_Option2 = 2;
C_Option3 = 4;
C_Option4 = 8;
and then test membership with a bitwise and:
if (Options and C_Option2) > 0 then begin
...
end;
I've tried this, and it works, but it feels like working with sets would be more natural and use the type system better (even though I'm going outside the said type system to enumerate the sets).
Is there a better/safer way to enumerate all possible set combinations than enumerating the underlying integer representation?
Notes:
- I know that the integer values of a set are not guaranteed in theory (though I suspect they are in practice if you don't play with the enumeration numbering).
- There could be more than four options (yes, I know that it grows exponentially and if there are too many options the algorithm could take forever).
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
我知道这个问题很老了,但这是我的偏好,因为它对我来说简单而自然:
I know this question is quite old, but this is my preference since it's simple and natural to me :
尝试
Try
您的代码无法编译,因为您的枚举 (TMyOption) 的值少于 8 个,并且 Delphi 使用集合的最小可能大小(以字节为单位)。因此,字节变量将适合您。
如果您的集合包含超过 8 个但少于 16 个可能的元素,则可以使用 Word(而不是整数)。
对于大于 16 但小于 32 的 DWord 变量和类型转换。
对于超过 32 个可能的元素,我认为更好的方法是使用字节数组或类似的东西。
Your code does not compile because your enumeration (TMyOption) have less than 8 values, and Delphi utilize the minimum possible size (in bytes) for sets. Thus, a byte variable will work for you.
If you have a set with more than 8 but less than 16 possible elements, a Word will work (and not an integer).
For more than 16 but less than 32 a DWord variable and typecast.
For more than 32 possible elements, I think a better approach is to use an array of bytes or something like that.
500 - 内部服务器错误的答案可能是最简单的。
另一种不太可能因选项数量的变化而中断的方法是声明一个布尔数组,并打开/关闭它们。但这比使用纯整数要慢。主要优点是,您无需更改所使用的整数类型,并且如果您有超过 32 个选项,则可以使用它。
500 - Internal Server Error's answer is probably the most simple.
Another approach that would less likely to break with changes to the number of options would be to declare an array of boolean, and switch them on/off. This is slower than working with pure integers though. The main advantage, you won't need to change the integer type you use, and you can use it if you have more than 32 options.
从 Integer 转换为 Set 是不可能的,但是 Tondrej 曾经写过 关于
SetToString
和StringToSet
的博客文章,其中公开了您的内容希望在SetOrdValue
方法中:您的代码将变成这样:
--jeroen
Casting from an Integer to a Set is not possible, but Tondrej once wrote a blog article on
SetToString
andStringToSet
that exposes what you want in theSetOrdValue
method:Your code then would become this:
--jeroen
问题是您试图转换为集合类型而不是枚举类型。您可以在整数和枚举之间进行转换,因为两者都是序数类型,但不能转换为集合,因为它们使用您已经注意到的位字段。如果你使用:
它会起作用,尽管不是你想要的。
几个月前我遇到了同样的问题,并得出结论,你不能在 Delphi 中枚举集合的内容(至少在 Delphi 7 中),因为该语言没有在集合上定义此类操作。
编辑:看来你甚至可以在D7中看到对此答案的评论。
The problem is that you are trying to cast to the set type instead of the enumerated type. You can cast between integer and enumerated because both are ordinal types, but you can't cast to a set because they use bitfiels as you already noted. If you use:
it would work, although is not what you want.
I had this same problem a few months ago and came to the conclusion that you can't enumerate the contents of a set in Delphi (at least in Delphi 7) because the language doesn't define such operation on a set.
Edit: It seems that you can even in D7, see coments to this answer.