Array operations with n-dimensional array using LINQ (C #)

Suppose we have a gear array

int[][] a = { new[] { 1, 2, 3, 4 }, new[] { 5, 6, 7, 8 }, new[] { 9, 10, 11, 12 } }; 

To get the sum of the second row and the sum of the second column, you can write both lines of code, respectively:

 int rowSum = a[1].Sum(); int colSum = a.Select(row => row[1]).Sum(); 

But if we have a two-dimensional array definition

 int[,] a = { { 1, 2, 3, 4 }, { 5, 6, 7, 8 }, { 9, 10, 11, 12 } }; 

the above code will not work due to compiler 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 is: how to use LINQ methods with n-dimensional arrays, but not jagged? And where is the method for converting a rectangular array into a notched one?

PS I tried to find the answer in the documentation, but without result.

+8
arrays c # linq
source share
6 answers

LINQ to Objects is based on the IEnumerable <T> Interface , that is, a one-dimensional sequence of values. This means that it does not mix well with n-dimensional data structures such as toothless arrays, although this is possible.

You can create a one-dimensional sequence of integers that are indexed into an 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]); 
+15
source share

About your question "How to use LINQ methods with n-dimensional arrays":

You cannot use most LINQ methods with an n-dimensional array, because such an array implements only IEnumerable , but not IEnumerable<T> , and most LINQ extension methods are extension methods for IEnumerable<T> .

About another question: see dtb answer.

+3
source share

To add dtb to the solution, a more general way of iterating over all elements of an array:

 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 extremely useless, because we create coordinate tuples even for those elements that we end up filtering with Where , but if you don’t know what selection criteria will be in advance, this is the way to go (or not - this is more like an exercise than what you would like to do in practice).

I can also imagine how this can be expanded for arrays of any rank (not just 2D) using a recursive lambda and something like Tuple , but this crosses the territory of masochism.

+3
source share

There is no built-in way to repeat a row or column in a 2D array. However, it is not difficult to create your own method. See This class for an implementation that is enumerable for a row and column.

 public static class LINQTo2DArray { public static IEnumerable<T> Row<T>(this T[,] Array, int Row) { for (int i = 0; i < Array.GetLength(1); i++) { yield return Array[Row, i]; } } public static IEnumerable<T> Column<T>(this T[,] Array, int Column) { for (int i = 0; i < Array.GetLength(0); i++) { yield return Array[i, Column]; } } } 

You can also smooth the array using a.Cast<int>() , but then you lose all the column / row information

+1
source share

A simpler method is performed as shown below.

  var t = new List<Tuple<int, int>>(); int[][] a = t.Select(x => new int[]{ x.Item1, x.Item2}).ToArray(); 
0
source share

The simplest LINQ method that I can see to perform these operations on rows and columns in a two-dimensional array is to define the following searches:

 var cols = a .OfType<int>() .Select((x, n) => new { x, n, }) .ToLookup(xn => xn.n % a.GetLength(1), xn => xn.x); var rows = a .OfType<int>() .Select((x, n) => new { x, n, }) .ToLookup(xn => xn.n / a.GetLength(1), xn => xn.x); 

Now you can simply do this:

 var firstColumnSum = cols[0].Sum(); 

As for the n-dimensional, it gets too painful ... Sorry.

-one
source share

All Articles