Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Array.create and jagged array

Tags:

arrays

f#

Can't understand the reason of such behavior:

let example count = 
    let arr = Array.create 2 (Array.zeroCreate count)
    for i in [0..count - 1] do
        arr.[0].[i] <- 1
        arr.[1].[i] <- 2
    arr

example 2 |> Array.iter(printfn "%A")

Print:

[|2; 2|]
[|2; 2|]

https://dotnetfiddle.net/borMmO

If I replace:

let arr = Array.create 2 (Array.zeroCreate count)

to:

let arr = Array.init 2 (fun _ -> Array.zeroCreate count)

Everything will work as expected:

let example count = 
    let arr = Array.init 2 (fun _ -> Array.zeroCreate count)
    for i in [0..count - 1] do
        arr.[0].[i] <- 1
        arr.[1].[i] <- 2
    arr

example 2 |> Array.iter(printfn "%A")

Print:

[|1; 1|]
[|2; 2|]

https://dotnetfiddle.net/uXmlbn

I think the reason is the fact that the array - a reference type. But I want to understand why this is happening. Since I didn't expect such results.

like image 311
FoggyFinder Avatar asked Jan 07 '23 00:01

FoggyFinder


1 Answers

When you write:

let arr = Array.create 2 (Array.zeroCreate count)

You are creating an array where each element is a reference to the same array. This means that mutating a value using arr.[0] also mutates the value in arr.[1] - because the two array elements are pointing to the same mutable array. You end up with:

[| x  ; x |]
    \  /
 [| 0; 0 |]

When you write:

let arr = Array.init 2 (fun _ -> Array.zeroCreate count)

The provided function is called for each position in the arr array and so you'll end up with different array for each element (and so arr.[0] <> arr.[1]). You end up with:

     [| x ;  y |]
       /       \
[| 0; 0 |]   [| 0; 0 |]
like image 131
Tomas Petricek Avatar answered Jan 15 '23 04:01

Tomas Petricek