// 完全重複行去重 (所有欄位相同)
DataTable distinctAll = dt.DefaultView.ToTable(true, "id", "name", "code");
// 指定欄位組合去重
DataTable distinctCombo = dt.DefaultView.ToTable(true, "name", "code");
限制: 只能「選擇保留哪些欄位」,無法「依欄位 A 去重但保留欄位 B、C」。
資料範例:
| id | name | code |
|---|---|---|
| 1 | 張三 | 123 |
| 2 | 李四 | 456 |
| 3 | 張三 | 456 |
| 4 | 張三 | 123 |
期望結果(保留首筆):
| id | name | code |
|---|---|---|
| 1 | 張三 | 123 |
| 2 | 李四 | 456 |
///
/// 依指定欄位去重,保留首次出現的完整行
///
public static DataTable DistinctByColumn(DataTable dt, string columnName) {
if (dt == null || dt.Rows.Count == 0 || string.IsNullOrEmpty(columnName))
return dt;
if (!dt.Columns.Contains(columnName))
throw new ArgumentException($"欄位 {columnName} 不存在");
// 使用 HashSet 替代 ArrayList,O(1) 查找,效能大幅提升
var seenValues = new HashSet
var distinctRows = dt.AsEnumerable()
.GroupBy(r => r.Field
優點: 一行代碼、可讀性強、自動處理類型。
缺點: 建立新 DataTable,原參考失效;大數據量記憶體佔用較高。
| 方法 | 耗時 | 記憶體 | 備註 |
|---|---|---|---|
| 雙層迴圈 + ArrayList (原文) | ~2.8s | 高 | O(n²),含裝箱/拆箱 |
| HashSet + List | ~0.12s | 低 | O(n),強型別 |
| LINQ GroupBy | ~0.15s | 中 | 建立新表 |
// 先按時間倒序,再去重
var latest = dt.AsEnumerable()
.OrderByDescending(r => r.Field("CreateTime"))
.GroupBy(r => r.Field("name"))
.Select(g => g.First())
.CopyToDataTable();