使用LINQ(C#)的n维数组的数组运算

假设我们有一个锯齿状的数组

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

要获得第二行和第二列之和的总和,可以分别写入两个代码行:

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

但是如果我们有二维数组的定义

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

由于编译器错误,上述代码将无效:

 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?) 

那么,问题是:如何使用具有n维数组的LINQ方法,而不是锯齿状的数组? 并且是将矩形数组转换为锯齿状的方法?

PS我试图在文档中找到答案,但没有结果。

LINQ to Objects基于IEnumerable 接口 ,即一维值序列。 这意味着它与n-dimensional数据结构(如非锯齿状数组)不能很好地混合,尽管它是可能的。

您可以生成索引到n维数组的一维整数序列:

 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]); 

关于您的问题“如何使用具有n维数组的LINQ方法”:

你不能将大多数LINQ方法与维数组一起使用,因为这样的数组只实现IEnumerable而不是IEnumerable并且大多数LINQ扩展方法是IEnumerable扩展方法。

关于另一个问题:请参阅dtb的回答。

要添加到dtb的解决方案,迭代数组的所有项的更一般方法是:

 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 })); 

现在:

 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]); 

当然,这是非常浪费的,因为我们正在创建坐标元组,即使对于那些我们最终会用Where过滤掉的项目,如果你事先不知道选择标准是什么,这是要走的路(或者不是) – 这看起来更像是一种练习,而不是你想要在练习中做的事情。

我还可以想象如何使用递归lambda和类似Tuple之类的任何等级(不仅仅是2D)的数组扩展,但是这会跨越到受虐狂领域。

2D数组没有任何内置的迭代行或列的方式。 尽管如此,创建自己的方法并不困难。 请参阅此类以获取行和列的可枚举实现。

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

您也可以使用a.Cast()展平数组,但随后会丢失有关列/行的所有信息

一种更简单的方法就是如下所示

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

我可以看到在二维数组上执行这些类型的行和列操作的最简单的LINQ方法是定义以下查找:

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

现在你可以简单地这样做:

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

至于n维,它只是太痛苦了…抱歉。