首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何在C#中用函数语句替换for-循环?

如何在C#中用函数语句替换for-循环?
EN

Stack Overflow用户
提问于 2010-04-15 16:18:11
回答 18查看 18.2K关注 0票数 35

一位同事曾经说过,每当我写一个for-循环时,上帝就会杀死一只小猫。

当被问及如何避免for-循环时,他的回答是使用函数式语言。但是,如果您使用的是一种非功能语言,比如C#,那么有什么技术可以避免for-循环或通过重构来消除它们呢?也许是用lambda的表情和LINQ?如果是这样的话,是怎么做的?

问题

因此,问题归结为:

  1. 为什么for-循环不好?或者,在什么情况下,for-循环要避免,为什么?
  2. 您能否提供C#代码示例,说明它以前的样子,即使用循环,以及之后没有循环?
EN

回答 18

Stack Overflow用户

回答已采纳

发布于 2010-04-15 16:23:28

在操作某些数据集并希望转换、筛选或聚合元素的情况下,函数式结构通常比for-循环更清楚地表达您的意图。

当您想要重复执行某些操作时,循环非常合适。

例如

代码语言:javascript
复制
int x = array.Sum();

更清楚地表达你的意图

代码语言:javascript
复制
int x = 0;
for (int i = 0; i < array.Length; i++)
{
    x += array[i];
}
票数 31
EN

Stack Overflow用户

发布于 2010-04-15 17:45:12

为什么for-循环不好?或者,在什么情况下,for-循环要避免,为什么?

如果您的同事有函数式编程,那么他可能已经熟悉避免for循环的基本原因:

折叠/映射/过滤器涵盖了列表遍历的大多数用例,并很好地用于函数组合。For-循环不是一个很好的模式,因为它们不能组合。

大多数情况下,您遍历列表以折叠(聚合)、映射或筛选列表中的值。这些高级函数已经存在于每一种主流的函数式语言中,所以您很少看到函数代码中使用的for-循环成语。

高阶函数是函数组合的基本要素,这意味着你可以很容易地将简单的函数组合成更复杂的东西。

要给出一个非平凡的例子,请使用命令语言考虑以下几点:

代码语言:javascript
复制
let x = someList;
y = []
for x' in x
    y.Add(f x')

z = []
for y' in y
    z.Add(g y')

在函数式语言中,我们可以编写map g (map f x),或者可以使用map (f . g) x消除中间列表。原则上,我们可以从命令式版本中删除中间列表,这会稍微有所帮助--但不会有多大帮助。

命令式版本的主要问题是for-循环是实现细节。如果你想要改变这个函数,你就会改变它的实现--你最终会修改很多代码。

举个例子,您是如何以必要的方式编写map g (filter f x)的?因为您不能重用映射和映射的原始代码,所以需要编写一个新的函数来过滤和映射。如果您有50种映射方法和50种过滤方法,那么如何需要50^50函数,或者您需要模拟使用命令模式将函数作为一流参数传递的能力(如果您曾经尝试过用Java进行函数式编程,您就会明白这是一场噩梦)。

回到功能领域,您可以泛化map g (map f x),使您可以根据需要使用filterfold交换map

代码语言:javascript
复制
let apply2 a g b f x = a g (b f x)

并使用apply2 map g filter fapply2 map g map fapply2 filter g filter f或任何您需要的东西来称呼它。在现实世界中,您可能永远不会编写这样的代码,您可能会使用以下方法来简化它:

代码语言:javascript
复制
let mapmap g f = apply2 map g map f
let mapfilter g f = apply2 map g filter f

高阶函数和函数组合为您提供了一个您无法从命令式代码中获得的抽象级别。

抽象出循环的实现细节,让我们无缝地将一个循环交换为另一个.

记住,for-循环是一个实现细节.如果需要更改实现,则需要更改每个for-循环。

映射/折叠/过滤抽象出循环。因此,如果您想要更改您的循环的实现,您可以在这些函数中更改它。

现在,您可能会想知道为什么要抽象出一个循环。考虑将项从一种类型映射到另一种类型的任务:通常,项目一次映射一个,顺序地映射,并且独立于所有其他项。大多数情况下,像这样的地图都是并行化的主要候选。

不幸的是,顺序映射和并行映射的实现细节不能互换。如果您的代码中有大量的顺序映射,并且希望将它们替换为并行映射,那么您有两个选择:在代码库中复制/粘贴相同的并行映射代码,或者将映射逻辑抽象成两个函数mappmap。一旦你走了第二条路,你就已经进入了函数式编程领域。

如果您理解函数组合的目的,并抽象出实现细节(甚至是像循环这样琐碎的细节),那么您可以首先了解函数编程是如何和为什么如此强大的。

票数 17
EN

Stack Overflow用户

发布于 2010-04-15 16:25:20

  1. 因为循环并不坏。有许多非常有效的理由来保持for循环。
  2. 通过在C#中使用LINQ对for循环进行重新处理,您通常可以“避免”for循环,后者提供了一种更具声明性的语法。这可以是好的,也可以是坏的,取决于情况:

比较以下几点:

代码语言:javascript
复制
var collection = GetMyCollection();
for(int i=0;i<collection.Count;++i)
{
     if(collection[i].MyValue == someValue)
          return collection[i];
}

vs foreach:

代码语言:javascript
复制
var collection = GetMyCollection();
foreach(var item in collection)
{
     if(item.MyValue == someValue)
          return item;
}

对LINQ:

代码语言:javascript
复制
var collection = GetMyCollection();
return collection.FirstOrDefault(item => item.MyValue == someValue);

就我个人而言,这三种选择都有各自的位置,我都会用到它们。这是一个为您的场景使用最合适的选项的问题。

票数 14
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/2647073

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档