将foreach转换为Linq

时间:2015-07-02 18:01:33

标签: c# linq

当前代码:

对于MapEntryTable中的每个元素,检查属性IsDisplayedColumnIsReturnColumn,如果它们为true,则将该元素添加到另一组列表中,其运行时间为{{ 1}},会有很多元素都将这两个属性都设为false,因此不会添加到循环中的任何列表中。

O(n)

以下是执行相同操作的Linq版本:

 foreach (var mapEntry in MapEntryTable)
 {
   if (mapEntry.IsDisplayedColumn)
      Type1.DisplayColumnId.Add(mapEntry.OutputColumnId);

   if (mapEntry.IsReturnColumn)
      Type1.ReturnColumnId.Add(mapEntry.OutputColumnId);
 }

我正在将所有这些foreach代码转换为linq,因为我正在学习它,但我的问题是:

  • 在这种情况下,我是否可以获得Linq转换的任何优势,还是不利?

  • 使用Linq

  • 是否有更好的方法

更新:

考虑一下条件,列表中的1000个元素中的80个元素都具有false属性,然后在哪里为我提供了快速查找具有给定条件的元素的好处。

MapEntryTable.Where(x => x.IsDisplayedColumn == true).ToList().ForEach(mapEntry => Type1.DisplayColumnId.Add(mapEntry.OutputColumnId)); MapEntryTable.Where(x => x.IsReturnColumn == true).ToList().ForEach(mapEntry => Type1.ReturnColumnId.Add(mapEntry.OutputColumnId)); 是一种自定义类型,其中包含Type1个结构List<int>DisplayColumnId

5 个答案:

答案 0 :(得分:7)

List不是LINQ方法。这是Where的一种方法。它不仅不是LINQ的一部分,它还非常反对LINQ的价值和模式。 Eric Lippet explains this in a blog post是他在C#编译团队中的主要开发人员时编写的。

你的“LINQ”方法也是:

  • 完全不必要地复制要添加到列表中的所有项目,既浪费时间和内存,又与LINQ执行查询时延迟执行的目标冲突。
  • 实际上不是查询,但foreach (var mapEntry in MapEntryTable.Where(entry => mapEntry.IsDisplayedColumn)) list1.DisplayColumnId.Add(mapEntry.OutputColumnId); foreach (var mapEntry in MapEntryTable.Where(entry => mapEntry.IsReturnColumn)) list2.ReturnColumnId.Add(mapEntry.OutputColumnId); 运算符除外。您正在处理查询中的项目,而不是执行查询。 LINQ是查询工具,而不是用于操作数据集的工具。
  • 您正在迭代源序列两次。这可能是也可能不是问题,取决于源序列实际是什么以及迭代它的成本是多少。

使用LINQ的解决方案就像它设计的一样,就像使用它一样:

# -*- coding: utf-8 -*-
from flask.ext.script import Manager
from extension import make_celery
from app import create_app

app = create_app()

celery = make_celery(app)

答案 1 :(得分:1)

我会说坚持使用foreach循环的原始方式,因为你只是在列表中重复了一次。

你的linq也应该更像这样:

list1.DisplayColumnId.AddRange(MapEntryTable.Where(x => x.IsDisplayedColumn).Select(mapEntry => mapEntry.OutputColumnId));       

list2.ReturnColumnId.AddRange(MapEntryTable.Where(x => x.IsReturnColumn).Select(mapEntry => mapEntry.OutputColumnId));

答案 2 :(得分:1)

foreach vs Linq ForEach的表现几乎完全相同,彼此在纳秒之内。假设您在测试时在两个版本的循环中都有相同的内部逻辑。

然而,for循环优于两个边缘。 for(int i; i&lt; count; ++ i)比两者都快得多。因为for循环不依赖于IEnumerable实现(开销)。 for循环编译为x86寄存器索引/跳转代码。它维护一个增量器,然后由你在循环中通过它的索引检索项目。

使用Linq ForEach循环确实有一个很大的缺点。你不能摆脱循环。如果你需要这样做,你必须维护一个类似“breakLoop = false”的布尔值,将其设置为true,并且如果breakLoop为true,则每次递归退出...在那里执行不好。其次你不能使用continue,而是使用“return”。

我从不使用Linq的foreach循环。

如果您正在处理linq,例如

List<Thing> things = .....;
var oldThings = things.Where(p.DateTime.Year < DateTime.Now.Year);

内部将与linq联系并仅返回年份少于当年的项目。凉爽..

但如果我这样做:

List<Thing> things = new List<Thing>();

foreach(XElement node in Results) {
    things.Add(new Thing(node));
}

我不需要为每个循环使用linq。即使我做了......

foreach(var node in thingNodes.Where(p => p.NodeType == "Thing") {
    if (node.Ignore) {
        continue;
    }
    thing.Add(node);
}

即使我能像

那样写清洁工具
foreach(var node in thingNodes.Where(p => p.NodeType == "Thing" && !node.Ignore) {
    thing.Add(node);
}

没有任何理由我能想到这样做..&gt;

   things.ForEach(thing => {
       //do something
       //can't break
       //can't continue
       return; //<- continue
   });

如果我想要最快的循环,

for (int i = 0; i < things.Count; ++i) {
    var thing = things[i];
    //do something
}

会更快。

答案 3 :(得分:1)

您的LINQ不太正确,因为您将Where的结果转换为List,然后使用ForEach对这些结果进行伪迭代以添加到另一个列表。使用ToListAddRange将序列转换或添加到列表中。

示例,覆盖list1(如果它实际上是List<T>):

list1 = MapEntryTable.Where(x => x.IsDisplayedColumn == true)
.Select(mapEntry => mapEntry.OutputColumnId).ToList();

或追加:

list1.AddRange(MapEntryTable.Where(x => x.IsDisplayedColumn == true)
.Select(mapEntry => mapEntry.OutputColumnId));

答案 4 :(得分:0)

在C#中,要在一次调用中执行您想要的功能,您必须编写自己的分区方法。如果您愿意使用F#,则可以使用List.Partition<'T>

https://msdn.microsoft.com/en-us/library/ee353782.aspx