Assume we have a jagged array
int[][] a = { new[] { 1, 2, 3, 4 }, new[] { 5, 6, 7, 8 }, new[] { 9, 10, 11, 12 } };
To get a sum of second row and sum of second column, it can be written both code lines respectively:
int rowSum = a[1].Sum();
int colSum = a.Select(row => row[1]).Sum();
But if we have definition of 2-dimensional array
int[,] a = { { 1, 2, 3, 4 }, { 5, 6, 7, 8 }, { 9, 10, 11, 12 } };
the above-cited code will not work due to compiller errors:
Error 1 Wrong number of indices inside []; expected 2
Error 2 'int[*,*]' does not contain a definition for 'Select' and no extension method 'Select' accepting a first argument of type 'int[*,*]' could be found (are you missing a using directive or an assembly reference?)
So, the question: How to use LINQ methods with n-dimensional arrays, but not jagged ones? And is where a method to convert rectangular array to jagged?
P.S. I tried to find the answer in documentation, but without result.
LINQ to Objects is based on the IEnumerable<T> Interface, i.e. a one-dimensional sequence of values. This means it doesn't mix well with n-dimensional data structures like non-jagged arrays, although it's possible.
You can generate one-dimensional sequence of integers that index into the n-dimensional array:
int rowSum = Enumerable.Range(0, a.GetLength(1)).Sum(i => a[1, i]);
int colSum = Enumerable.Range(0, a.GetLength(0)).Sum(i => a[i, 1]);
About your question "How to use LINQ methods with n-dimensional arrays":
You can't use most LINQ methods with a n dimensional array, because such an array only implements IEnumerable
but not IEnumerable<T>
and most of the LINQ extension methods are extension methods for IEnumerable<T>
.
About the other question: See dtb's answer.
To add to dtb's solution, a more general way of iterating over all items of the array would be:
int[,] b = { { 1, 2, 3, 4 }, { 5, 6, 7, 8 }, { 9, 10, 11, 12 } };
var flattenedArray = Enumerable.Range(0, b.GetLength(0))
.SelectMany(i => Enumerable.Range(0, b.GetLength(1))
.Select(j => new { Row = i, Col = j }));
And now:
var rowSum2 = flattenedArray.Where(t => t.Row == 1).Sum(t => b[t.Row, t.Col]);
var colSum2 = flattenedArray.Where(t => t.Col == 1).Sum(t => b[t.Row, t.Col]);
Of course this is ultra-wasteful as we are creating coordinate tuples even for those items that we will end up filtering out with Where
, but if you don't know what the selection criteria will be beforehand this is the way to go (or not -- this seems more like an excercise than something you 'd want to do in practice).
I can also imagine how this might be extended for arrays of any rank (not just 2D) using a recursive lambda and something like Tuple
, but that crosses over into masochism territory.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With