2011-09-06 84 views
8

假設我們有一個鋸齒形陣列數組操作

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

但是,如果我們有2維數組的定義

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

以上引用的代碼將無法正常工作由於compiller錯誤:

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方法,但不是鋸齒狀的?並且在哪裏將矩形陣列轉換爲鋸齒狀?

P.S.我試圖在文檔中找到答案,但沒有結果。

+0

的多維數組是不是真正的(大量)支持C#:-( – xanatos

回答

15

LINQ to Objects基於IEnumerable<T> Interface,即一維值序列。這意味着它不能與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]); 
+1

+1:有趣的方法 –

3

關於你的問題:「如何使用LINQ方法與n維數組」:

你不能將大多數LINQ方法與維數組一起使用,因爲這樣的數組僅實現IEnumerable而不是IEnumerable<T>,並且大多數LINQ擴展方法是IEnumerable<T>的擴展方法。

關於其他問題:請參閱dtb的答案。

3

爲了增加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)的數組擴展,但是這會跨越到受虐狂的領域。

1

二維數組沒有任何內置的遍歷行或列的方式。儘管如此,創建自己的這種方法並不難。查看這個類獲得一個可以枚舉的行和列的實現。

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

您也可以拼合使用a.Cast<int>()的數組,但你會再寬鬆所有關於列/行

-1

最簡單的LINQ唯一的方法我可以看到做這些類型的行和列的操作上的信息二維數組定義以下查詢:

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

現在,你可以簡單地這樣做:

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

至於n維,它只是太痛苦...抱歉。

0

更簡單的方法是做像下面

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