【发布时间】:2015-06-29 14:34:11
【问题描述】:
我需要创建一个数字组合列表。数字很小,所以我可以使用byte 而不是int。但是,它需要许多嵌套循环才能获得每种可能的组合。我想知道是否有更有效的方式来做我所追求的。到目前为止的代码是:
var data = new List<byte[]>();
for (byte a = 0; a < 2; a++)
for (byte b = 0; b < 3; b++)
for (byte c = 0; c < 4; c++)
for (byte d = 0; d < 3; d++)
for (byte e = 0; e < 4; e++)
for (byte f = 0; f < 3; f++)
for (byte g = 0; g < 3; g++)
for (byte h = 0; h < 4; h++)
for (byte i = 0; i < 2; i++)
for (byte j = 0; j < 4; j++)
for (byte k = 0; k < 4; k++)
for (byte l = 0; l < 3; l++)
for (byte m = 0; m < 4; m++)
{
data.Add(new [] {a, b, c, d, e, f, g, h, i, j, k, l, m});
}
我正在考虑使用 BitArray 之类的东西,但我不确定如何合并它。
任何建议将不胜感激。或者,也许这是做我想做的最快的方式?
编辑 几个要点(很抱歉我没有把这些放在原始帖子中):
- 数字和它们的顺序(2、3、4、3、4、3、3 等)非常重要,因此使用 Generating Permutations using LINQ 之类的解决方案无济于事,因为每个 ' 列中的最大值' 不同
- 我不是数学家,如果我没有正确使用“排列”和“组合”等技术术语,我深表歉意:)
- 我确实需要一次填充所有这些组合 - 我不能只根据索引抓取一个或另一个
- 使用
byte比使用int更快,我保证。拥有 67m+ 字节数组而不是 ints 在内存使用方面也好很多 - 我的最终目标是寻找一种更快的替代嵌套循环的方法。
- 我考虑过使用并行编程,但由于我想要实现的迭代性质,我找不到成功的方法(即使使用
ConcurrentBag)——但我很高兴证明是错误的:)
结论
Caramiriel 提供了一个很好的微优化,可以缩短循环时间,因此我已将该答案标记为正确。 Eric 还提到,预先分配 List 会更快。但是,在这个阶段,嵌套循环似乎实际上是最快的方法(我知道,令人沮丧!)。
如果您想准确地尝试使用StopWatch 进行基准测试,请使用 13 个循环,每个循环最多计数 4 个 - 列表中大约有 67m+ 行。在我的机器上(i5-3320M 2.6GHz)做优化版本大约需要2.2s。
【问题讨论】:
-
尝试使用 linq,如果你使用的是多核处理器,那么 Parrallel.for
-
根据我所看到的,这些不是排列,而是几个非常小的(2-4 个元素)集合的组合是正确的,或者您确实想要 的所有/某些排列一套?
-
我假设你已经搜索了 bing.com/search?q=c%23+permutation+enumerable 并且出于某种原因(帖子中未提及)决定反对现有的答案,如 stackoverflow.com/questions/4319049/…... 考虑列出你查看并决定反对的选项问题更好。
-
如果这与性能有关:您可以预先分配列表(构造函数)并展开一些循环,但我认为仅此而已......除了预先计算和存储这些数字。循环(开销)可能是所有循环中成本最高的,因为主体内部的操作量很少。
-
@benpage:为什么需要预先生成所有组合?为什么不在需要的时候从它的索引中生成一个组合呢?
标签: c# combinations