nik
nik

Reputation: 1784

Combining same length arrays into one 2d array in f#

I have asked this question before in c# here and there wasnt really a succinct way of doing this. I m now trying to do the same in fsharp and see how that goes.

I have two arrays that are same length and type and I would like to combine them into one with same length and 2 columns. I have this code that does this:

let twoDimensionalArray (arr1:array<'a>) (arr2:array<'a>) = 
    let rws = arr1|> Array.length
    Array2D.init rws 1 (fun i j -> arr1.[i], arr2.[i]) 

To be honest this surprises me a bit as I would have thought there should be a 2 in the column dimension like this:

Array2D.init rws 2 (fun i j -> arr1.[i], arr2.[i]) 

but if I change this to 2 then I get this:

val it : (float * float) [,] = [[(1.0, 3.0); (1.0, 3.0)]
                            [(2.0, 4.0); (2.0, 4.0)]]

for this data:

let arr1 = [| 1.0; 2.0 |]
let arr2=  [|3.0; 4.0 |]

Why?

Also I would really like to write this more generacally, so if the first array has 2 columns and the second 1, I get a 3 column matrix and so forth. I tried this:

let MultiArray (arr1:array<'a>) (arr2:array<'a>)  = 
    let rws = arr1.Length
    let c1 = arr1.GetLength(1)
    let c2 = arr2.GetLength(1)
    let cols = c1+c2
    Array2D.init rws cols (fun i j -> arr1.[i], arr2.[i]) 

But this is flawed.

Could you please let me know how I could do this? Also why my first function works but I think is wrong?

Thanks

Thanks John! Working solution:

let MultiArray (inp:float[][]) =
    let cls = inp |> Array.length
    let rows = inp.[0] |> Array.length
    Array2D.init rows cls (fun i j -> inp.[j].[i])

Sample data and use:

let arr1 = [|1.0 ; 4.0; 6.0;5.;8.|] 
let arr2= [|7.0; 8.0; 9.0;9.;10. |] 
let inp = [| arr1; arr2; arr1|]

MultiArray inp;;
val it : float [,] = [[1.0; 7.0; 1.0]
                  [4.0; 8.0; 4.0]
                  [6.0; 9.0; 6.0]
                  [5.0; 9.0; 5.0]
                  [8.0; 10.0; 8.0]]

Upvotes: 0

Views: 979

Answers (2)

Alex
Alex

Reputation: 1

Nice Solution; Would suggest to change this lines to:

let c1 = arr1.GetLength(0)
let c2 = arr2.GetLength(0)

In my case I got an index out of bound with 1 as described above.

However I prefer 'generica' as well:

Array2D.init count rows (fun i j -> inp.[j].[i])

Upvotes: -1

John Palmer
John Palmer

Reputation: 25516

So the reason for the unexpected version of the first code is you are creating a 2D array of tuples - rather than a 2D array of values. You actually should set the size of the first dimension to 1 in this case as the second dimension is hiding in the fact that the tuple has more variables.

A simple version which creates an actual 2D array would be

Array2D.init rws 2 (fun i j ->match j with |0 -> arr1.[i] |1 -> arr2.[i]) 

A more generic version would take in an array of arrays as input like so

let MultiArray (inp:float[][])
    let count = inp |> Array.length
    let rows = inp.[0] |> Array.length
    Array2D.init count rows (fun i j -> inp.[j].[i]

Upvotes: 3

Related Questions