如何在不带来太多开销的情况下使这个循环更具功能性

时间:2012-09-19 15:40:03

标签: f#

 for i in a..b do
     res <- res * myarray.[i]
 res

我必须使用

  Array.fold (*) 1 (Array.sub myarray a (b - a + 1))

,我认为这是相当缓慢而不是那么简洁?

3 个答案:

答案 0 :(得分:5)

不知道你是否会更好地找到它,但你可以这样做:

Seq.fold (fun r i -> r * myarray.[i]) 1 {a .. b}

答案 1 :(得分:4)

Daniel的解决方案非常简洁,我认为它应该与for循环一样高效,因为它不需要克隆数组。

如果你想要一个更简洁的解决方案,那么你可以使用索引器而不是Array.sub,它需要克隆数组的某些部分,但它看起来非常整洁:

myarray.[a .. b] |> Seq.fold (*) 1

这会克隆数组的一部分,因为切片操作会返回一个数组。您可以定义自己的切片操作,将元素返回为seq<'T>(因此不会克隆整个数组):

module Array =
  let slice a b (arr:'T[]) = 
    seq { for i in a .. b -> arr.[i] }

使用此功能,您可以写:

myarray |> Array.slice a b |> Seq.fold (*) 1

我相信这更直接地表达了您尝试实现的功能。与性能一样 - 您应该测量性能以确定是否需要进行此类优化,或者第一个版本是否足够快以达到您的目的。

答案 2 :(得分:4)

如果你关注速度,那么除非你是原型,否则我会回避使用seq。要么坚持使用for循环,要么重写为递归函数。您给出的示例是简单的,有时更复杂的问题更好地表示为递归。

let rec rangeProduct a b total (array : _[]) =
    if a <= b then
        rangeProduct (a + 1) b (total * array.[a]) array
    else
        total

let res = myArray |> rangeProduct a b res

这里没有开销,它尽可能快,没有突变,而且功能正常。