首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

LINQ 雙重 Select 投影與分組轉置:代碼邏輯深度解析與修正

     編輯:程式設計綜合問答

原始代碼與問題

var query = data.Select((x, r) => x.Select((v, c) => new { r, c, v }));
var result = query.GroupBy(x => x.c).Select(x => x.Select(y => y.v).OrderBy(x => x.r).ToArray()).ToArray();

提問者表示「看不懂」,並追問含義。最佳回答指出第一行 Select 應為 SelectMany,否則類型不匹配。

數據結構假設

假設 data 為 IEnumerable<IEnumerable<T>>(如 List<List<int>>),表示二維表格:

  • 外層索引 r = 行號
  • 內層索引 c = 列號
  • v = 單元格值

逐行邏輯拆解(修正版)

步驟 1:展平為座標三元組流

// 修正:SelectMany 將每行的「列投影序列」展平為單一序列
var coords = data.SelectMany((row, r) => row.Select((val, c) => new { Row = r, Col = c, Val = val }));
// 結果:{Row=0,Col=0,Val=a}, {Row=0,Col=1,Val=b}, {Row=1,Col=0,Val=c} ...

步驟 2:按列分組

var grouped = coords.GroupBy(t => t.Col);
// 每組包含同一列的所有行:Group[0] = { (0,0,a), (1,0,c), ... }

步驟 3:組內按行排序並提取值

var columns = grouped
    .OrderBy(g => g.Key) // 確保列順序 0,1,2...
    .Select(g => g.OrderBy(t => t.Row).Select(t => t.Val).ToArray())
    .ToArray();
// 結果:columns[0] = 第0列所有行值數組,columns[1] = 第1列...

整體效果:矩陣轉置

若 data 為 [[1,2,3], [4,5,6]](2行3列),result 為 [[1,4], [2,5], [3,6]](3行2列)。**這正是矩陣的轉置操作**。

等價的查詢語法寫法(更易讀)

var result = (from row in data.Select((r, i) => new { Idx = i, Val = r })
              from cell in row.Val.Select((v, c) => new { Row = row.Idx, Col = c, Val = v })
              group cell by cell.Col into g
              orderby g.Key
              select g.OrderBy(c => c.Row).Select(c => c.Val).ToArray()
             ).ToArray();

性能與內存提示

  • 上述寫法會將所有數據物化到內存(多次 ToArray),大數據集慎用。
  • 流式處理可改用 IEnumerable 鏈式調用,末端才 ToList。
  • 若 data 本身是 T[,] 二維數組,直接雙重 for 迴圈轉置效率最高,無 GC 壓力。

應用場景

  • CSV/Excel 行列互換導出
  • 矩陣運算預處理
  • 數據透視表後端聚合

總結

原代碼意圖是 **LINQ 實現矩陣轉置**,但第一行誤用 Select 導致類型為 IEnumerable<IEnumerable<Anonymous>> 而非扁平序列,修正為 SelectMany 後邏輯通順。理解「展平→分組→排序→投影」四步驟,即可掌握此類複雜 LINQ 轉換模式。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved