Initialize a Jagged Array the LINQ Way
-
11-09-2019 - |
Question
I have a 2-dimensional jagged array (though it's always rectangular), which I initialize using the traditional loop:
var myArr = new double[rowCount][];
for (int i = 0; i < rowCount; i++) {
myArr[i] = new double[colCount];
}
I thought maybe some LINQ function would give me an elegant way to do this in one statement. However, the closest I can come up with is this:
double[][] myArr = Enumerable.Repeat(new double[colCount], rowCount).ToArray();
The problem is that it seems to be creating a single double[colCount]
and assigning references to that intsead of allocating a new array for each row. Is there a way to do this without getting too cryptic?
Solution
double[][] myArr = Enumerable
.Range(0, rowCount)
.Select(i => new double[colCount])
.ToArray();
OTHER TIPS
What you have won't work as the new
occurs before the call to Repeat
. You need something that also repeats the creation of the array. This can be achieved using the Enumerable.Range
method to generate a range and then performing a Select
operation that maps each element of the range to a new array instance (as in Amy B's answer).
However, I think that you are trying to use LINQ where it isn't really appropriate to do so in this case. What you had prior to the LINQ solution is just fine. Of course, if you wanted a LINQ-style approach similar to Enumerable.Repeat
, you could write your own extension method that generates a new item, such as:
public static IEnumerable<TResult> Repeat<TResult>(
Func<TResult> generator,
int count)
{
for (int i = 0; i < count; i++)
{
yield return generator();
}
}
Then you can call it as follows:
var result = Repeat(()=>new double[rowCount], columnCount).ToArray();
The behavior is correct - Repeat()
returns a sequence that contains the supplied object multiple times. You can do the following trick.
double[][] myArr = Enumerable
.Repeat(0, rowCount)
.Select(i => new double[colCount])
.ToArray();
You can't do that with the Repeat
method : the element
parameter is only evaluated once, so indeed it always repeats the same instance. Instead, you could create a method to do what you want, which would take a lambda instead of a value :
public static IEnumerable<T> Sequence<T>(Func<T> generator, int count)
{
for (int i = 0; i < count; i++)
{
yield return generator();
}
}
...
var myArr = Sequence(() => new double[colCount], rowCount).ToArray();
I just wrote this function...
public static T[][] GetMatrix<T>(int m, int n)
{
var v = new T[m][];
for(int i=0;i<m; ++i) v[i] = new T[n];
return v;
}
Seems to work.
Usage:
float[][] vertices = GetMatrix<float>(8, 3);
What about
var myArr = new double[rowCount, colCount];
or
double myArr = new double[rowCount, colCount];
Reference: http://msdn.microsoft.com/en-us/library/aa691346(v=vs.71).aspx