I have faced with a strange behavior in c#. I created a int[][] array like this:
int[][] m_dist = Enumerable.Repeat(Enumerable.Repeat(-1, m.Length).ToArray(), m.Length).ToArray();
Array looks like this:
-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,
Later on when I tried to modify a single array element I was supraised because not only one item was changed but a complete int[] array:
m_dist[1][1] = 0;
Output was:
-1,0,-1,-1,-1,-1,
-1,0,-1,-1,-1,-1,
-1,0,-1,-1,-1,-1,
-1,0,-1,-1,-1,-1,
-1,0,-1,-1,-1,-1,
-1,0,-1,-1,-1,-1,
I suspected that something happens during the array creation therefore I simplified it like this:
//int[][] m_dist = Enumerable.Repeat(Enumerable.Repeat(-1, m.Length).ToArray(), m.Length).ToArray();
int[][] m_dist = new int[m.Length][];
for (int i = 0; i < m_dist.Length; i )
{
m_dist[i] = new int[m.Length];
for (int j = 0; j < m_dist[i].Length; j )
{
m_dist[i][j] = -1;
}
}
With this kind of initialization the addressing was flawless.
Of course I can live with this solution, but I would like to understand what happened during my first attempt.
If somebody could explain that would be great!
Debug code:
int[][] m_dist = Enumerable.Repeat(Enumerable.Repeat(-1, m.Length).ToArray(), m.Length).ToArray();
for (int i = 0; i < m_dist.Length; i )
{
for (int j = 0; j < m_dist[i].Length; j )
{
Console.Write(m_dist[i][j] ",");
}
Console.Write("\n");
}
Console.WriteLine();
m_dist[1][1] = 0;
for ( int i = 0; i< m_dist.Length; i )
{
for (int j = 0; j < m_dist[i].Length; j )
{
Console.Write(m_dist[i][j] ",");
}
Console.Write("\n");
}
Console.WriteLine();
Of course I can live with this solution, but I would like to understand what happened during my first attempt.If somebody could explain that would be great!
CodePudding user response:
Let me unpack this line so you can see what exactly happens:
int[][] m_dist = Enumerable.Repeat(Enumerable.Repeat(-1, m.Length).ToArray(), m.Length).ToArray();
Unrolling the expressions we get:
int[] array = Enumerable.Repeat(-1, m.Length).ToArray();
int[][] m_dist = Enumerable.Repeat(array, m.Length).ToArray();
You create a single array
filled with -1
values, and then create an array m_dist
that contains repeated references to that array. Every entry in m_dist
points to array
, so editing an element through any of these references is reflected through all of those references.
What you want to do is create m.Length
separate arrays:
int[][] m_dist = Enumerable.Range(0, m.Length)
.Select(_ => Enumerable.Repeat(-1, m.Length).ToArray())
.ToArray();
CodePudding user response:
In your first attempt, the problem is that you are creating multiple references to the same inner array, rather than creating a new array for each element in the outer array. This can be seen in the following line of code:
int[][] m_dist = Enumerable.Repeat(Enumerable.Repeat(-1, m.Length).ToArray(), m.Length).ToArray();
Here, you are using the Enumerable.Repeat()
method to create a new array filled with the value -1
, and then calling the ToArray()
method to convert it into an array of integers. You then call Enumerable.Repeat()
again, passing the previously created array as an argument, to create a new array filled with references to the original array. Finally, you call ToArray()
again to convert this into a 2D array of integers.
The problem is that, because the inner array is only created once and then referenced multiple times, modifying any element in the inner array will affect all of the references to that array in the outer array. This is why, when you modify the element at m_dist[1][1]
, the entire inner array is modified, rather than just that one element.
In your second attempt, you are creating a new inner array for each element in the outer array, which avoids this problem. This can be seen in the following code:
int[][] m_dist = new int[m.Length][];
for (int i = 0; i < m_dist.Length; i )
{
m_dist[i] = new int[m.Length];
for (int j = 0; j < m_dist[i].Length; j )
{
m_dist[i][j] = -1;
}
}
Here, you are using a for loop to create a new inner array for each element in the outer array, and then initializing each element in the inner array to -1
. Because each inner array is created independently, modifying an element in one inner array will not affect the other inner arrays, so the problem you were seeing in your first attempt does not occur.