在上一篇
C# WinForm 動態產生 DataGridView,動態新增資料 手把手教學
中點閱率還不錯,只是沒有人留言,看來大家都學得很成功,都沒有什麼問題...😅,於是再來教點進階的 —— 關於樞紐分析表
最近我們公司在徵才,其中一題面試的題目簡化後是這樣的:
傳入資料:
將上述資料整理後輸出為下表:
其實非常簡單,於是就來帶大家實作一次,首先先想辦法將資料放到程式內:先建立物件
放入資料:
好了,簡單的做完了,那接下來該怎麼辦呢?其實也不難,只要將資料依照姓名群組起來,再排列順序,並把沒有的填入預設值(補 0)即可,如果你熟悉 LINQ,那應該知道群組就是使用 GroupBy,然後再使用匿名類別將得到的資料整理一下,就差不多了。
延伸閱讀:C# 使用 GroupBy 將資料分組
程式碼:
輸出訊息:
不過到這裡先暫停一下,輸出是能輸出,不過寫太死了,也有很多重複的程式碼,其實進階一點我們可以讓「科目」是動態的,假設今天還沒考國文,總不可能大家國文都先填入 0 分把?正常情況下應該是會空白或是沒有這個科目的欄位,所以我們先找到所有科目名稱然後去重複,動態決定要顯示哪些欄位:
接下來就是建立資料表和設定欄位:
將每個學生的成績依照欄位填入,並加入到資料表中:
動態建立 DataGridView 和係結資料表:
延伸閱讀:C# WinForm 動態產生 DataGridView,動態新增資料教學
執行結果:
嗯,看起來 100 分!
參考資料:
Microsoft.Learn - DataGridView Class
最近我們公司在徵才,其中一題面試的題目簡化後是這樣的:
傳入資料:
姓名 | 科目 | 考試類型 | 分數 |
---|---|---|---|
小花 | 國文 | 期中考 | 68 |
小花 | 英文 | 期中考 | 77 |
小花 | 數學 | 期中考 | 87 |
小花 | 物理 | 期中考 | 66 |
小王 | 國文 | 期中考 | 45 |
小王 | 英文 | 期中考 | 50 |
小王 | 數學 | 期中考 | 78 |
小王 | 物理 | 期中考 | 63 |
小陳 | 國文 | 期中考 | 75 |
將上述資料整理後輸出為下表:
姓名 | 國文 | 英文 | 數學 | 物理 |
---|---|---|---|---|
小花 | 68 | 77 | 87 | 66 |
小王 | 45 | 50 | 78 | 63 |
小陳 | 75 | 0 | 0 | 0 |
其實非常簡單,於是就來帶大家實作一次,首先先想辦法將資料放到程式內:先建立物件
public sealed class Test
{
public string Student { get; set; }
public string Course { get; set; }
public string ExamType { get; set; }
public int Score { get; set; }
}
放入資料:
public static List<Test> Tests = new()
{
new Test { Student = "小花", Course = "國文", ExamType = "期中考", Score = 68 },
new Test { Student = "小花", Course = "英文", ExamType = "期中考", Score = 77 },
new Test { Student = "小花", Course = "數學", ExamType = "期中考", Score = 87 },
new Test { Student = "小花", Course = "物理", ExamType = "期中考", Score = 66 },
new Test { Student = "小王", Course = "國文", ExamType = "期中考", Score = 45 },
new Test { Student = "小王", Course = "英文", ExamType = "期中考", Score = 50 },
new Test { Student = "小王", Course = "數學", ExamType = "期中考", Score = 78 },
new Test { Student = "小王", Course = "物理", ExamType = "期中考", Score = 63 },
new Test { Student = "小陳", Course = "國文", ExamType = "期中考", Score = 75 },
};
好了,簡單的做完了,那接下來該怎麼辦呢?其實也不難,只要將資料依照姓名群組起來,再排列順序,並把沒有的填入預設值(補 0)即可,如果你熟悉 LINQ,那應該知道群組就是使用 GroupBy,然後再使用匿名類別將得到的資料整理一下,就差不多了。
延伸閱讀:C# 使用 GroupBy 將資料分組
程式碼:
var list = Tests
.Where(x => x.ExamType == "期中考")
.GroupBy(x => x.Student)
.Select(x =>
new
{
Student = x.Key,
國文 = x.Where(y => y.Course == "國文").Select(y => y.Score).FirstOrDefault(),
英文 = x.Where(y => y.Course == "英文").Select(y => y.Score).FirstOrDefault(),
數學 = x.Where(y => y.Course == "數學").Select(y => y.Score).FirstOrDefault(),
物理 = x.Where(y => y.Course == "物理").Select(y => y.Score).FirstOrDefault()
}
)
.ToList();
list.ForEach(x =>Console.WriteLine($"姓名: {x.Student}, 國文: {x.國文}, 英文: {x.英文}, 數學: {x.數學}, 物理: {x.物理}"));
輸出訊息:
姓名: 小花, 國文: 68, 英文: 77, 數學: 87, 物理: 66
姓名: 小王, 國文: 45, 英文: 50, 數學: 78, 物理: 63
姓名: 小陳, 國文: 75, 英文: 0, 數學: 0, 物理: 0
不過到這裡先暫停一下,輸出是能輸出,不過寫太死了,也有很多重複的程式碼,其實進階一點我們可以讓「科目」是動態的,假設今天還沒考國文,總不可能大家國文都先填入 0 分把?正常情況下應該是會空白或是沒有這個科目的欄位,所以我們先找到所有科目名稱然後去重複,動態決定要顯示哪些欄位:
List<string> columns = Tests.Select(x => x.Course).Distinct().ToList(); // 所有科目名稱
接下來就是建立資料表和設定欄位:
DataTable dataTable = new();
List<string> columns = Tests.Select(x => x.Course).Distinct().ToList(); // 所有科目名稱
dataTable.Columns.Add("姓名");
columns.ForEach(x => dataTable.Columns.Add(x));
將每個學生的成績依照欄位填入,並加入到資料表中:
Tests
.Where(x => x.ExamType == "期中考")
.GroupBy(x => x.Student)
.Select(x =>
{
var row = dataTable.NewRow();
row[0] = x.Key;
foreach (var test in x)
{
row[test.Course] = test.Score;
}
return row;
}
).ToList()
.ForEach(x => dataTable.Rows.Add(x));
動態建立 DataGridView 和係結資料表:
DataGridView dataGridView = new DataGridView();
this.Controls.Add(dataGridView); // 新增到當前的 Form 中
dataGridView.Dock = DockStyle.Fill; // 填滿視窗
dataGridView.DataSource = dataTable;
延伸閱讀:C# WinForm 動態產生 DataGridView,動態新增資料教學
執行結果:
嗯,看起來 100 分!
參考資料:
Microsoft.Learn - DataGridView Class
留言
張貼留言
如果有任何問題、建議、想說的話或文章題目推薦,都歡迎留言或來信: a@ruyut.com