当前代码:
对于MapEntryTable
中的每个元素,检查属性IsDisplayedColumn
和IsReturnColumn
,如果它们为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
答案 0 :(得分:7)
List
不是LINQ方法。这是Where
的一种方法。它不仅不是LINQ的一部分,它还非常反对LINQ的价值和模式。 Eric Lippet explains this in a blog post是他在C#编译团队中的主要开发人员时编写的。
你的“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
对这些结果进行伪迭代以添加到另一个列表。使用ToList
或AddRange
将序列转换或添加到列表中。
示例,覆盖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>