当前位置:  开发笔记 > 编程语言 > 正文

对Enumerable <T>中的所有元素执行特定操作

如何解决《对Enumerable<T>中的所有元素执行特定操作》经验,为你挑选了5个好方法。

我有一个Enumerable并且正在寻找一种方法,允许我为每个元素执行一个动作,有点像Select然后是副作用.就像是:

string[] Names = ...;
Names.each(s => Console.Writeline(s));

要么

Names.each(s => GenHTMLOutput(s));   
// (where GenHTMLOutput cannot for some reason receive the enumerable itself as a parameter)

我试过了Select(s=> { Console.WriteLine(s); return s; }),但它没有打印任何东西.



1> Jay Bazuzi..:

一个快速简便的方法是:

Names.ToList().ForEach(e => ...);


ToList()将评估IEnumerable中的每个节点,这意味着在该点完成任何延迟评估.我宁愿通过制作自己的扩展方法尽可能晚地离开这个.
这有一个很大的问题.如果你做ToList,那么所有对象*必须*一次存在于内存中.如果源是DB,那么至少使用IEnumerable,您的对象可以在完成后卸载.使用ToList,您可以为大型数据集耗尽内存!不要使用它!
是的,这种方法有很多缺点,但我很惊讶它们不是一个问题,这种简单的方法效果很好.事实上,我的大部分序列都是<100个元素.(也许你正在做比我更有趣的编程.)

2> Jeff Yates..:

您正在寻找目前仅存在于List通用集合中的难以捉摸的ForEach.网上有很多关于微软应该或不应该将其作为LINQ方法添加的讨论.目前,你必须自己动手:

public static void ForEach(this IEnumerable value, Action action)
{
  foreach (T item in value)
  {
    action(item);
  }
}

虽然该All()方法提供了类似的能力,但它的用例是对每个项目而不是动作执行谓词测试.当然,可以说服它执行其他任务,但这会稍微改变语义并使其他人更难以解释您的代码(即这是All()用于谓词测试还是动作?).


使用All会是一个坏主意 - 如果其中任何一个Func 返回false,那么执行将结束.

3> Joel Coehoor..:

免责声明:这篇文章不再类似于我原来的答案,而是融入了我从那以后获得的七年经验.我进行了编辑,因为这是一个高度重视的问题,现有的答案都没有涵盖所有角度.如果您想查看我的原始答案,可以在此帖子的修订历史记录中找到.


在这里了解的第一件事是像C#LINQ操作Select(),All(),Where(),等,其根源都在于函数式编程.我们的想法是为.Net世界带来一些更有用和更易于使用的函数式编程部分.这很重要,因为函数式编程的一个关键原则是这些操作应该没有副作用.很难低估这一点.添加ForEach()each()操作不仅仅是在其他linq运算符的函数式编程范围之外,而是与它们直接对立.

但我明白这感到不满意.你有一个真正需要解决的问题.为什么所有这些象牙塔哲学都会妨碍可能真正有用的东西呢?

当时在C#设计团队工作的Eric Lippert可以帮助我们.他建议只使用传统的each()循环:

[ForEach()]为语言增加了零新的表征能力.这样做可以让你重写这个完全清晰的代码:

ForEach()

进入这段代码:

foreach

他的观点是,当你仔细研究你的语法选项时,你不会从foreach(Foo foo in foos){ statement involving foo; }扩展到传统foos.ForEach(foo=>{ statement involving foo; });循环获得任何新东西.我部分不同意.想象一下你有这个:

 foreach(var item in Some.Long(and => possibly)
                         .Complicated(set => ofLINQ)
                         .Expression(to => evaluate)
 {
     // now do something
 } 

此代码模糊了含义,因为它将ForEach()关键字与循环中的操作分开.它还列出了定义循环操作序列的操作之前的循环命令.想要将这些操作放在第一位然后在查询定义的末尾使用loop命令会感觉更自然.此外,代码只是丑陋.看起来能写这个会好得多:

Some.Long(and => possibly)
   .Complicated(set => ofLINQ)
   .Expression(to => evaluate)
   .ForEach(item => 
{
    // now do something
});

然而,即使在这里,我最终还是以埃里克的观点出现了.我意识到你上面看到的代码正在呼唤一个额外的变量.如果你有一组复杂的LINQ表达式,你可以先将LINQ表达式的结果赋给一个新变量,然后在代码中添加一些有价值的信息:

var queryForSomeThing = Some.Long(and => possibly)
                        .Complicated(set => ofLINQ)
                        .Expressions(to => evaluate);
foreach(var item in queryForSomeThing)
{
    // now do something
}

这段代码感觉更自然.它将foreach关键字放回到循环的其余部分旁边,并在查询定义之后.最重要的是,变量名称可以添加新信息,这将有助于未来的程序员试图理解LINQ查询的目的.同样,我们看到所需的foreach操作员确实没有为该语言添加新的表达能力.

但是,我们仍然缺少假设foreach扩展方法的两个特征:

    它不可组合.我不能添加另外ForEach()ForEach()或者.Where()一后GroupBy()与其余代码回路内联,而无需创建一个新的语句.

    这不是懒惰.这些操作立即发生.例如,它不允许我有一个表单,其中用户选择操作作为较大屏幕中的一个字段,直到用户按下命令按钮才对其起作用.此表单可能允许用户在执行命令之前改变主意.使用LINQ查询这是完全正常的(简单的),但不是那么简单OrderBy().

当然,您可以制作自己的foreach扩展方法.其他几个答案已经实现了这种方法; 这并不是那么复杂.但是,我觉得这是不必要的.现有的方法已经适合我们想要从语义和操作角度做的事情.上述两个缺失的功能都可以通过使用现有的foreach运营商来解决.

ForEach()适合上述两个例子描述的变换或投影.但请记住,我仍然会避免产生副作用.调用Select()应返回原始对象或投影.这有时可以通过使用匿名类型或动态对象来帮助(当且仅在必要时).如果您需要将结果保留在原始列表变量中,您可以随时调用Select()并将其分配回原始变量.我在这里补充说,我喜欢Select()在更具体的类型上尽可能地使用变量.

myList = myList.Select(item => new SomeType(item.value1, item.value2 *4)).ToList();

综上所述:

    只是坚持.ToList()大部分时间.

    如果IEnumerable 真的不这样做(可能不像你想象的那么频繁),请使用foreach

    当您需要使用时foreach,您通常可以通过投射到匿名类型来避免(程序可见的)副作用.



4> JaredPar..:

不幸的是,在当前版本的LINQ中没有内置的方法可以做到这一点.框架团队忽略了添加.ForEach扩展方法.现在在下面的博客上就此进行了很好的讨论.

http://blogs.msdn.com/kirillosenkov/archive/2009/01/31/foreach.aspx

虽然添加一个很容易.

public static void ForEach(this IEnumerable enumerable, Action action) {
  foreach ( var cur in enumerable ) {
    action(cur);
  }
}



5> Tamas Czineg..:

您不能立即使用LINQ和IEnumerable进行此操作-您需要实现自己的扩展方法,或者使用LINQ将枚举强制转换为数组,然后调用Array.ForEach():

Array.ForEach(MyCollection.ToArray(), x => x.YourMethod());

请注意,由于值类型和结构的工作方式,如果集合属于值类型,并且您以这种方式修改集合的元素,则它将对原始集合的元素没有影响。

推荐阅读
360691894_8a5c48
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有