Recursively iterating over an array in F #
This is a pretty basic query, but I'm having trouble with the F # syntax. I need to create a function to iterate over a two-dimensional array recursively, incrementing a counter every time a condition is met. In this case, the function takes an identifier as a parameter and then checks how many times that identifier is present inside the internal arrays. I was thinking about something like this:
let runner array count =
match count with
|0 -> (exit loop)
|n -> (perform function)
runner array count-1
For the general structure of a recursive iteration function. However, there are a few things that I'm not sure about. What are the conditions for breaking out of a recursive loop (i.e. Base case) in F #? How can I structure this so that it crosses over both the main and sub-range in order to check the ID? And how do I do this so that the counter increments with each iteration of the recursive loops, assuming I cannot use mutable functions? Any help would be appreciated.
source to share
There is a more general way to do this. You want to dump the 2d array. They don't have a fold defined in the Array2D module, but you can write one.
let fold f state (arr: 'a [,]) =
Seq.cast<'a> arr
|> Seq.fold f state
We're cheating a little here, casting gives us a flat sequence of elements from the array, which we later turn into a regular fold. So now you can do:
array |> fold (fun counter e -> if cond e then counter+1 else counter) 0
where cond is the condition you want to check.
source to share
I find 2D arrays a little awkward in F #, but here's how you could do it:
let recursivelyCountID ID (matr : 'T[,]) =
let rec dim1 acc index0 index1 =
if index1 > matr.GetUpperBound 1 then
acc
else
let newAcc = if matr.[index0, index1] = ID then acc+1 else acc
dim1 newAcc index0 (index1+1)
let rec dim0 acc index0 =
if index0 > matr.GetUpperBound 0
then acc
else dim0 (acc + (dim1 0 index0 0)) (index0+1)
dim0 (matr.GetLowerBound 0) (matr.GetLowerBound 1)
If you use an array of arrays instead, you can use functions in the standard F # module:
let IDsInInnerArray ID xs = xs |> Array.sumBy (fun i -> if i = ID then 1 else 0)
let totalIDs ID xss = xss |> Array.map (fun xs -> IDsInInnerArray ID xs) |> Array.sum
Edit: I was confused not noticing that 2D arrays implement IEnumerable, so instead of the previous code working with arrays of arrays, the direct function for 2D arrays would be:
let totalIDs ID (matr : 'T[,]) =
matr
|> Seq.cast<'T>
|> Seq.sumBy (fun i -> if i = ID then 1 else 0)
... using the Seq.cast function, as scrwtp shows in his answer.
source to share