Samuel Jenks
Samuel Jenks

Reputation: 1182

Write a for loop that increments the index twice

In F# the documentation provides two standard for loops. The for to expression is the loop which provides an index, incremented or decremented per item, depending on whether it is a for to or for downto expression.

I want to loop over an array and increment a variable amount of times; specifically twice. in C# this is very straight forward:

for(int i = 0; i < somelength; i += 2) { ... }

How would I achieve the same thing in F#?

Upvotes: 3

Views: 1976

Answers (3)

Tomas answer is correct and elegant it is worth considering that a in F# loop with an increment of 2 is slower than a loop with increment of 1.

Faster loops in F#:

let print x = printfn "%A" x

// Only increment by +1/-1 allowed for ints    
let case0 () = for x = 0 to 10 do print x
let case1 () = for x = 10 downto 0 do print x
// Special handling in F# compiler ensures these are fast
let case2 () = for x in 0..10 do print x
let case3 (vs : int array) = for x in vs do print x
let case4 (vs : int list) = for x in vs do print x
let case5 (vs : string) = for x in vs do print x

Slower loops in F#:

let print x = printfn "%A" x

// Not int32s
let case0 () = for x in 0L..10L do print x
let case1 () = for x in 0s..10s do print x
let case2 () = for x in 0.0..10.0 do print x
// Not implicit +1/-1 increment
let case3 () = for x in 0..1..10 do print x
let case4 () = for x in 10..-1..0 do print x
let case5 () = for x in 0..2..10 do print x
let case6 () = for x in 10..-2..0 do print x
// Falls back on seq for all cases except arrays, lists and strings
let case7 (vs : int seq) = for x in vs do print x
let case8 (vs : int ResizeArray) = for x in vs do print x
// Very close to fast case 2 but creates an unnecessary list
let case9 () = for x in [0..10] do print x

When F# compiler don't have special handling to ensure quick iteration it falls back on generic code that looks a bit like this:

use e = (Operators.OperatorIntrinsics.RangeInt32 0 2 10).GetEnumerator()
while enumerator.MoveNext() do
  print enumerator.Current

This might or might not be a problem to you but it's worth knowing about I think.

IMHO tail recursion is the way to loop as for and while has a kind of imperative taste to them and thanks to tail call optimization in F# tail recursion is fast if written correctly.

let rec loop i =
  if i < someLength then
    doSomething i
    loop (i + 2)
loop 0

Upvotes: 2

Guran
Guran

Reputation: 424

Tomas already answered your syntax question. Another answer suggests using tail recursion instead.

A third approach with a more f-sharpy feel to it would be something like this:

let myArray = [| 1; 2; 3 ; 4 |]

let stepper f step a = 
  a
  |> Array.mapi (fun x i -> if i % step = 0 then Some (f x) else None)
  |> Array.choose id

printfn "%A" <| stepper (fun x -> x * 2) 2 myArray
// prints [|2; 6|]

Upvotes: 1

Tomas Petricek
Tomas Petricek

Reputation: 243106

You can specify the step using the following syntax:

for x in 0 .. 2 .. somelength do 
  printfn "%d" x

For more information, see the documentation for the for .. in expression. More generally, you can also use this for iterating over any sequence (IEnumerable), so this behaves more like C# foreach.

Upvotes: 11

Related Questions