How would you make the folowing code functional with the same speed? In general, as an input I have a list of objects containing position coordinates and other stuff and I need to create a 2D array consisting those objects.
let m = Matrix.Generic.create 6 6 []
let pos = [(1.3,4.3); (5.6,5.4); (1.5,4.8)]
pos |> List.iter (fun (pz,py) ->
let z, y = int pz, int py
m.[z,y] <- (pz,py) :: m.[z,y]
)
It could be probably done in this way:
let pos = [(1.3,4.3); (5.6,5.4); (1.5,4.8)]
Matrix.generic.init 6 6 (fun z y ->
pos |> List.fold (fun state (pz,py) ->
let iz, iy = int pz, int py
if iz = z && iy = y then (pz,py) :: state else state
) []
)
But I guess it would be much slower because it loops through the whole matrix times the list versus the former list iteration…
PS: the code might be wrong as I do not have F# on this computer to check it.
It depends on the definition of “functional”. I would say that a “functional” function means that it always returns the same result for the same parameters and that it doesn’t modify any global state (or the value of parameters if they are mutable). I think this is a sensible definition for F#, but it also means that there is nothing “dis-functional” with using mutation locally.
In my point of view, the following function is “functional”, because it creates and returns a new matrix instead of modifying an existing one, but of course, the implementation of the function uses mutation.
Mutation-free version:
Now, if you wanted to make the implementation fully functional, then I would start by creating a matrix that contains
Some(pz, py)in the places where you want to add the new list element to the element of the matrix andNonein all other places. I guess this could be done by initializing a sparse matrix. Something like this:Then you should be able to combine the original matrix
mwith the newly createdelementsToAdd. This can be certainly done usinginit(however, having something likemap2would be maybe nicer):There is still quite likely some mutation hidden in the F# library functions (such as
initandinitSparse), but at least it shows one way to implement the operation using more primitive operations.EDIT: This will work only if you need to add at most single element to each matrix cell. If you wanted to add multiple elements, you’d have to group them first (e.g. using
Seq.groupBy)