【问题标题】:Convert Nested For Loops into a LINQ Expression将嵌套的 For 循环转换为 LINQ 表达式
【发布时间】:2013-03-05 10:25:24
【问题描述】:

请考虑以下代码:

    private ISet<int> CalcSumsOfTwoNums(IEnumerable<int> nums) {
        ISet<int> iset = new HashSet<int>();
        var asArray = nums.ToArray();

        for (var i = 0; i < asArray.Length - 2; i++) {
            for (var j = i; j < asArray.Length - 1; j++) {
                var sum = asArray[i] + asArray[j];
                if (sum <= MAX) {
                    iset.Add(sum);
                }
            }
        }

        return iset;
    }

将嵌套的for 循环语法转换为 LINQ 表达式或 LINQ 点表示法是否有意义?这是for 循环语法更合适的情况之一吗?我倾向于说for 循环在这里更好,因为我依赖于数组的索引位置,因为我正在通过它来获得结果集。

【问题讨论】:

  • 也许你应该解释一下循环的实际作用,以使其更容易?
  • 据我所知,Linq 具有常规循环的性能
  • @MarcinJuraszek - 我认为我试图发现的最重要的事情是,在 for 循环语法中,在 ij 上面保存数组索引的变量是计算总和的关键,我不明白如何将其转换为 LINQ 语法。 nums 中的值可以是任意值,例如 1 到 10。我返回 ISet 而不是 IEnumerable 以保证返回的值是唯一的。
  • 你为什么要首先使用 LINQ?当然,这对于某种操作来说很好,但乍一看我会说这不是其中之一。也许它是有意的,但数组的最后一个值不会与你在 for 循环中的限制一起使用。
  • @WiiMaxx:由于涉及到 lambda 函数,LINQ 通常性能较差。它们看起来很简单,但实际上在实现中相当复杂。对所有课程案例都没有关系。

标签: c# linq for-loop


【解决方案1】:

你可以试试下面的 Linq:

var asArray = nums.ToArray();
var result = (from n1 in asArray.Take(asArray.Length - 2)
              from n2 in asArray.Take(asArray.Length - 1)
              where n1 + n2 <= MAX
              select n1 + n2);

iset = new HashSet<int>(result);

它的输出和你的 sn-p 一样。

【讨论】:

  • 内部循环仍然从该集合的开头进行迭代。问题中的示例从外部循环中的实际位置开始内部循环:var j = i。结果是相同的,但您的解决方案中有几个不必要的迭代。
  • @MarcinJuraszek - 请再次检查!
  • 结果还可以,因为 HashSet 将重复项组合在一起 :) 但是您要计算每个总和两次:分别为 (i1, i2) 和 (i2, i1)。
【解决方案2】:
private static ISet<int> CalcSumsOfTwoNums2(IEnumerable<int> nums)
{
    // get List<int> from nums to get info about collection length
    var source = nums.ToList();

    // proper iteration
    var data = source.Take(source.Count - 1)
                     .SelectMany((e, ix) => source.Skip(ix)
                                                  .Take(source.Count - 1 - ix)
                                                  .Select(i => new { e, i }))
                     .Select(x => x.e + x.i)
                     .Where(x => x < MAX);

    // return HashSet instead of IEnumerable<int>
    return new HashSet<int>(data);
}

它返回与您的方法相同的结果。但是,我会继续使用您当前的解决方案。它会比 LINQ 有更好的性能。

【讨论】:

  • 上面的代码有一个小错误,那就是在最后一个Where 子句中,它应该是x &lt;= MAX 而不是x &lt; MAX
  • 我选择这个答案作为接受的答案,因为 MarcinJuraszek 的算法避免了计算每个总和两次的额外工作。此外,这个答案的运行速度大约快 2.5 倍,但并不比 for 循环语法快。
猜你喜欢
  • 2012-08-10
  • 2012-10-07
  • 2011-06-07
  • 2012-12-29
  • 2020-11-26
  • 1970-01-01
  • 2012-11-06
  • 1970-01-01
  • 2021-12-09
相关资源
最近更新 更多