这是遍历变量范围的更好方法吗?

时间:2019-04-27 10:11:50

标签: c#

考虑一个简单的方程:5 = 2 * a + 4 * b-3 * c

通过变量循环比使用多个for循环更好吗?

这有多个答案,但是为了找到方程式的答案,我使用了多个for循环,例如

for(int a = 1; a < 50; a++) {
  for(int b = 1; b < 50; b++) {
    for(int c = 1; c < 50; c++) {
      //validate
    }
  }
}

现在,对于此示例,这将不需要太多时间。但是,如果这要经过成千上万个条目的数据集,并且for循环的目标是看到,如果我可以找到一组优化的变量,那么它将花费一些时间。也许有3个以上。上面的方程只是一个例子。

是否有另一种更好的方法?可能是代码模式?我也很想看看我如何清理它,因为有很多嵌套。

我的验证逻辑已经被扔到BackgroundWorker中,并且我限制了计数,因此我可以利用100%的CPU,因此我主要考虑的是尽可能不进行for循环嵌套。

1 个答案:

答案 0 :(得分:1)

嵌套循环是最有效的方法,您可以通过Parallel.For设置外部循环很容易地并行化它。

int solutionsCount = 0;
Parallel.For(1, 50, a =>
{
    for (int b = 1; b < 50; b++)
        for (int c = 1; c < 50; c++)
            if (2 * a + 4 * b - 3 * c == 0) Interlocked.Increment(ref solutionsCount);
});

如果想花哨的话,可以创建一个自定义迭代器,该迭代器将产生所有排列:

private static IEnumerable<(int a, int b, int c)> Loop(int to1, int to2, int to3)
{
    for (int a = 1; a < to1; a++)
        for (int b = 1; b < to2; b++)
            for (int c = 1; c < to3; c++)
                yield return (a, b, c); // this is a ValueTuple<int, int, int>
}

并像这样使用它:

foreach (var p in Loop(50, 50, 50))
{
    // Do something with p.a, p.b and p.c
}

您甚至可以使用LINQ直接获得解决方案:

var solutions = Loop(50, 50, 50)
.Where(p => 2 * p.a + 4 * p.b - 3 * p.c == 0);
Console.WriteLine($"Solutions: {String.Join(", ", solutions)}");

...但是速度要慢10倍。

您甚至可以像这样使用纯LINQ:

var solutions = Enumerable.Range(1, 50 - 1)
.SelectMany(a => Enumerable.Range(1, 50 - 1)
.SelectMany(b => Enumerable.Range(1, 50 - 1)
.Where(c => 2 * a + 4 * b - 3 * c == 0)));

...具有与上一个相同的性能。通过在查询中链接AsParallel()(在第一个Enumerable.Range之后),它也可以并行化。