一位同事曾经说过,每当我写一个for-循环时,上帝就会杀死一只小猫。
当被问及如何避免for-循环时,他的回答是使用函数式语言。但是,如果您使用的是一种非功能语言,比如C#,那么有什么技术可以避免for-循环或通过重构来消除它们呢?也许是用lambda的表情和LINQ?如果是这样的话,是怎么做的?
问题
因此,问题归结为:
发布于 2010-04-15 16:23:28
在操作某些数据集并希望转换、筛选或聚合元素的情况下,函数式结构通常比for-循环更清楚地表达您的意图。
当您想要重复执行某些操作时,循环非常合适。
例如
int x = array.Sum();更清楚地表达你的意图
int x = 0;
for (int i = 0; i < array.Length; i++)
{
x += array[i];
}发布于 2010-04-15 17:45:12
为什么for-循环不好?或者,在什么情况下,for-循环要避免,为什么?
如果您的同事有函数式编程,那么他可能已经熟悉避免for循环的基本原因:
折叠/映射/过滤器涵盖了列表遍历的大多数用例,并很好地用于函数组合。For-循环不是一个很好的模式,因为它们不能组合。
大多数情况下,您遍历列表以折叠(聚合)、映射或筛选列表中的值。这些高级函数已经存在于每一种主流的函数式语言中,所以您很少看到函数代码中使用的for-循环成语。
高阶函数是函数组合的基本要素,这意味着你可以很容易地将简单的函数组合成更复杂的东西。
要给出一个非平凡的例子,请使用命令语言考虑以下几点:
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),使您可以根据需要使用filter或fold交换map:
let apply2 a g b f x = a g (b f x)并使用apply2 map g filter f、apply2 map g map f或apply2 filter g filter f或任何您需要的东西来称呼它。在现实世界中,您可能永远不会编写这样的代码,您可能会使用以下方法来简化它:
let mapmap g f = apply2 map g map f
let mapfilter g f = apply2 map g filter f高阶函数和函数组合为您提供了一个您无法从命令式代码中获得的抽象级别。
抽象出循环的实现细节,让我们无缝地将一个循环交换为另一个.
记住,for-循环是一个实现细节.如果需要更改实现,则需要更改每个for-循环。
映射/折叠/过滤抽象出循环。因此,如果您想要更改您的循环的实现,您可以在这些函数中更改它。
现在,您可能会想知道为什么要抽象出一个循环。考虑将项从一种类型映射到另一种类型的任务:通常,项目一次映射一个,顺序地映射,并且独立于所有其他项。大多数情况下,像这样的地图都是并行化的主要候选。
不幸的是,顺序映射和并行映射的实现细节不能互换。如果您的代码中有大量的顺序映射,并且希望将它们替换为并行映射,那么您有两个选择:在代码库中复制/粘贴相同的并行映射代码,或者将映射逻辑抽象成两个函数map和pmap。一旦你走了第二条路,你就已经进入了函数式编程领域。
如果您理解函数组合的目的,并抽象出实现细节(甚至是像循环这样琐碎的细节),那么您可以首先了解函数编程是如何和为什么如此强大的。
发布于 2010-04-15 16:25:20
比较以下几点:
var collection = GetMyCollection();
for(int i=0;i<collection.Count;++i)
{
if(collection[i].MyValue == someValue)
return collection[i];
}vs foreach:
var collection = GetMyCollection();
foreach(var item in collection)
{
if(item.MyValue == someValue)
return item;
}对LINQ:
var collection = GetMyCollection();
return collection.FirstOrDefault(item => item.MyValue == someValue);就我个人而言,这三种选择都有各自的位置,我都会用到它们。这是一个为您的场景使用最合适的选项的问题。
https://stackoverflow.com/questions/2647073
复制相似问题