Apply function to all elements of collection through LINQ
我最近刚开始和Linq合作,这太棒了。我想知道Linq是否允许我在不使用foreach的情况下将函数(任何函数)应用于集合的所有元素。类似于python lambda函数。
例如,如果我有一个int列表,我可以使用linq向每个元素添加一个常量吗?
如果我有一个DB表,我可以使用LINQ为所有记录设置一个字段吗?
我用C
一种常见的方法是在IEnumerable上添加自己的foreach泛型方法。这是我们在Morelinq得到的:
1 2 3 4 5 6 7 8 9
| public static void ForEach<T>(this IEnumerable<T> source, Action<T> action)
{
source.ThrowIfNull("source");
action.ThrowIfNull("action");
foreach (T element in source)
{
action(element);
}
} |
(其中ThrowIfNull是对任何引用类型的扩展方法,这是显而易见的。)
看看这是否是.NET 4.0的一部分会很有趣。这与Linq的功能风格背道而驰,但毫无疑问,很多人认为它很有用。
一旦你做到了,你就可以写一些东西,比如:
1 2
| people.Where(person => person.Age < 21)
.ForEach(person => person.EjectFromBar()); |
- 我从来没有真正理解人们必须这么做的冲动.forEach循环对我来说更易于阅读;在获取数据的"功能"部分和对其进行操作的"操作"部分之间进行分离有助于澄清算法的结构。
- 是的,我通常自己喜欢前臂环。另一方面,如果已经向您展示了要应用于每个元素的委托,我不确定在显式foreach循环中调用该委托是否更可读。我不会经常使用它,但偶尔它似乎是一个很好的解决方案。
- @Lodewijk:使用一种必须有副作用才能起作用的方法是什么样的?Where部分是功能性的……在我看来,ForEach部分不算多。
- 不在功能性部分。只是语法。
- Lodewijk:是的,这就是我怀疑你是否真的受益的地方。为什么代码看起来有些功能,但违反了功能性编程的正常目标?在EDCOX1×1循环上有什么好处?对我来说,感觉既不是一样东西也不是别的东西。
- 做一个就地的改变而不是返回新的类型绝对是可怕的。这会把大量程序员搞糊涂的。这样做的好处是不必嵌套前臂或编写丑陋的代码。一行程序可以非常可读。
- @你的意思是声明性的吗?
- @亚历克斯,也许不是。什么意思?这些"功能ISH"功能是扩展控制流的方法,"地图"特别得到了很多的喜爱。它使获取集合并对其中的所有内容应用函数变得容易。使用"map"而不是4行foreach是很好的,因为它显示的功能不那么含糊(想想零或一个索引头痛),而且更简洁。让map返回一个新集合而不是进行内联更改更标准,更通用。不过,这个"foreach"不是一个map函数,与常规的foreach循环相比,它的优势更小。
- @Lodewijk,关于声明性编程的基本内容是,它应该表示要做什么,而不是如何做。这听起来就像是你在那里之后,"不那么含糊不清","布雷弗"和"不是功能性的自私,只是语法"。就像通常的LINQ一样-一种更具声明性的方式来表示复杂的逻辑操作。
- 这与select()linq方法有什么不同?
- @Bkspugeon:Select是一个预测:1)它被懒惰地评估了;仅仅称它不会做任何事情。2)Select产生结果—ForEach不产生结果。
- @我有一个实际的用例。我需要在LINQ语句的管道之间插入一些日志记录
- @马丁:foreach在这方面帮不了你,但是一个记录然后返回其输入的select委托,或者一个记录然后返回true的where委托都可以工作…
- @琼斯基特,谢谢。我意识到我试过一次就没用了。我完全为这个问题找到了另一种方法,但下次我将考虑选择(…)方法。不过,在Select中引入副作用有点"淘气"。但我会活着。
- 我知道这是个老问题。我发现foreach在RXJS中非常有用,目前它感觉像是linq中的一个省略,我不认为它会混淆人们,因为foreach lambda的目的是修改项目或对它们做一些特定的事情,特别是在处理您绝对不想要新类型的ef实体时。我们的RXJS代码非常清晰和紧凑。感谢@jonsket的回答。我们不会一直使用,但有时它会为每个锅炉板节省很多钱。
使用Linq执行此操作的惯用方法是处理集合并返回一个以您想要的方式映射的新集合。例如,要向每个元素添加常量,您需要
1
| var newNumbers = oldNumbers.Select(i => i + 8); |
以功能性的方式执行此操作,而不是改变现有集合的状态,通常可以帮助您以一种既易于阅读又便于编译器分析的方式分离不同的操作。
如果您实际希望对集合的每个元素应用一个操作(具有与集合的实际内容无关的副作用的操作),那么这并不是Linq最适合的操作,尽管您可以使用Select(或编写自己的IEnumerable扩展方法,就像许多人一样在这种情况下,最好还是使用foreach循环。
- 更不用说在迭代过程中改变集合是危险的,甚至是不可能的,这取决于语言。
- 在C中,改变集合的元素是公平的游戏,但是添加到集合或从集合中移除可能会失败或产生不需要的结果。
- 使用select方法只对某些类型(如int)有帮助。如果要将列表中对象的属性设置为某个值,该怎么办?使用.foreach()不是更简单、更可扩展吗?
- 如果您已经知道新的值,那么通常(本着LINQ的精神),您会倾向于创建一个新的列表,其中包含适当的值,而不是更改旧的值。当然,如果您确实有一个列表,并且您真的想要更改这个特定的列表——可能它绑定到了某个对象上——那么.foreach()也可以。
- 如果以后不迭代结果,那么linq defer执行可能是Select的问题。
- @soviut ForEach不会改变集合。它可以-而且通常用于-编辑集合中的元素。个人而言,我会返回编辑过的收藏,但您的里程数可能会有所不同。
您还可以考虑并行处理,特别是如果您不关心顺序,更关心如何为每个项目完成某些工作:
1
| SomeIEnumerable<T>.AsParallel().ForAll( Action<T> / Delegate / Lambda ) |
例如:
1 2
| var numbers = new[] { 1, 2, 3, 4, 5 };
numbers .AsParallel().ForAll( Console .WriteLine ); |
Hth.
- 请注意asparallel().forall(),因为它会导致不可预知的结果。例如,当单击:myEnumerable.aspallel().forall(i as string=>otherDictionary.add(i,0))时,我有一个按钮来执行此代码。它将向OtherDictionary添加空作为键。我必须改写以使用FURACH循环。奇怪的。
- "YuSkaskura并不是真正的AsLeaveAuthor"。For()的错误——危险的位是使用多个线程之间的共享声明,然后"i为字符串"的转换是空键传递的可能原因。是否愿意分享一个更完整的代码示例,以获得关于如何改进的反馈?
哈哈,伙计,我几个小时前刚刚问过这个问题(有点……试试这个:
例子:
1
| someIntList.ForEach(i=>i+5); |
ForEach()是内置的.NET方法之一。
这将修改列表,而不是返回新列表。
- 请注意,这只适用于实际的list集合,除非您已经定义了自己的foreach方法。
- 我相信mquander指的是foreach没有在ienumerable上定义,只是list
- 是的,它在大多数情况下都不起作用,因为通常您会从链接查询中获取IEnumerable
- 我发现大多数时候我只需要添加.ToList().ForEach(...)。
或者你可以把它拆下来。
1
| Items.All(p => { p.IsAwesome = true; return true; }); |
- 这是黑客"所有"把它变成"foreach"。我有一种不好的感觉,这会误导一些新手,让他们认为"一切"的意思是"对所有元素执行"。
对于不支持foreach的集合,可以在Parallel类中使用静态foreach方法:
1 2
| var options = new ParallelOptions () { MaxDegreeOfParallelism = 1 };
Parallel .ForEach(_your_collection_, options, x => x ._Your_Method_ ()); |
你可以试试
1
| var foo = (from fooItems in context.footable select fooItems.fooID + 1); |
返回ID的+1列表,可以对select子句中的任何内容使用函数。
更新:正如jon skeet所建议的,这是我刚刚发布的代码片段的更好版本:
1
| var foo = context.footable.Select(foo => foo.fooID + 1); |
- 我建议在只需要进行简单投影的情况下,查询表达式是最重要的。我将使用"var foo=context.footable.select(foo=>foo.foo i d+1);"
我找到了一些方法来执行字典包含我的自定义类方法
1 2
| foreach (var item in this.Values.Where(p => p.IsActive == false))
item.Refresh(); |
其中"this"派生自:dictionary
1 2 3 4
| class MyCustomClass
{
public void Refresh(){}
} |