Reputation: 21767
for i in a..b do
res <- res * myarray.[i]
res
Do I have to use like
Array.fold (*) 1 (Array.sub myarray a (b - a + 1))
, which I believe is rather slow and not that concise?
Upvotes: 2
Views: 169
Reputation: 13862
If you're concerned with speed then I'd shy away from using seq unless you're prototyping. Either stick with the for loop or rewrite as a recursive function. The example you gave is simplistic and sometimes more complex problems are better represented as recursion.
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
There is no overhead here, it's as fast as possible, there is no mutation, and it's functional.
Upvotes: 4
Reputation: 243126
Daniel's solution is pretty neat and I think it should be nearly as efficient as the for
loop, because it does not need to clone the array.
If you wanted a more concise solution, then you can use indexer instead of Array.sub
, which does need to clone some part of the array, but it looks quite neat:
myarray.[a .. b] |> Seq.fold (*) 1
This clones a part of the array because the slicing operation returns an array. You could define your own slicing operation that returns the elements as seq<'T>
(and thus does not clone the whole array):
module Array =
let slice a b (arr:'T[]) =
seq { for i in a .. b -> arr.[i] }
Using this function, you could write:
myarray |> Array.slice a b |> Seq.fold (*) 1
I believe this more directly expresses the functionality that you're trying to implement. As always with performance - you should measure the performance to see if you need to make such optimizations or if the first version is fast enough for your purpose.
Upvotes: 4
Reputation: 47914
Don't know if you'll find it any better, but you could do:
Seq.fold (fun r i -> r * myarray.[i]) 1 {a .. b}
Upvotes: 5