[英]How do I remove rows from a DataTable up to a certain date?
我在過濾 DataTable 時遇到問題,比如DtFromExcel
。 DataTable 沒有 header 行,它以實際數據行開頭,如下所示。
1 | 05/01/2020 Fri | ABC | XYZ | ...
2 | 05/01/2020 Fri | AAA | WKV | ...
3 | 05/02/2020 Sat | BCD | OPQ | ...
4 | 05/03/2020 Sun | CDE | RST | ...
5 | 05/03/2020 Sun | EFA | FAY | ...
6 | 05/03/2020 Sun | AXG | EAS | ...
7 | 05/04/2020 Mon | DEF | LMN | ...
8 | 05/04/2020 Mon | SXA | YTR | ...
9 | 05/05/2020 Tue | DAF | AAG | ...
第二列包含帶有一些額外字符串(星期幾)的特定日期,這些行按此日期列排序。 可以有多個具有相同日期的行。
現在,我想刪除日期列包含某個日期的行以及之前的任何行。 例如,如果某個日期是05/04/2020
,那么我需要刪除第 8 行之前的所有行,以便剩余的 DataTable 看起來像
9 | 05/05/2020 Tue | DAF | AAG | ...
我的問題是,首先我不知道如何過濾沒有列名的 DataTable。 我想過在不覆蓋第一個實際數據行的情況下分配 header 行,但似乎這是很多工作,只是為了過濾。 其次,我不確定如何使用這些條件((a)第二列包含某個日期AND
以及(b)任何包含該日期之前的日期的行)。
private void DeleteRows(DateTime certainDate){
DataRow[] targetRowsToDelete = dtFromExcel.Select(/* Not sure what to put in here */);
foreach (DataRow row in targetRowsToDelete)
{
if (Convert.ToDateTime(row[1].ToString().Split(c" ")[0]) <= certainDate)
DtFromExcel.Rows.Remove(row);
}
}
我不想遍歷整個 DataTable,因為這個過程經常發生在我的程序中。
如果您使用空構造函數創建一個沒有名稱的DataColumn
,文檔說明...
創建時,
DataColumn
object 沒有默認的ColumnName
或Caption
。 當您將其添加到DataColumnCollection
時,如果尚未為ColumnName
分配名稱,則將生成默認名稱("Column1"
、"Column2"
等)。
...因此創建和加載這樣的DataTable
...
const string Input = @"1 | 05/01/2020 Fri | ABC | XYZ | ...
2 | 05/01/2020 Fri | AAA | WKV | ...
3 | 05/02/2020 Sat | BCD | OPQ | ...
4 | 05/03/2020 Sun | CDE | RST | ...
5 | 05/03/2020 Sun | EFA | FAY | ...
6 | 05/03/2020 Sun | AXG | EAS | ...
7 | 05/04/2020 Mon | DEF | LMN | ...
8 | 05/04/2020 Mon | SXA | YTR | ...
9 | 05/05/2020 Tue | DAF | AAG | ...";
DtFromExcel = new DataTable();
for (int i = 0; i < 5; i++)
{
DataColumn column = new DataColumn();
Console.WriteLine($"Column {i} has ColumnName \"{column.ColumnName}\"");
DtFromExcel.Columns.Add(column);
Console.WriteLine($"Column {i} has ColumnName \"{column.ColumnName}\"");
}
foreach (string line in Input.Split("\r\n"))
{
string[] fields = line.Split(" | ");
DtFromExcel.Rows.Add(fields);
}
...生產此 output...
Column 0 has ColumnName "" Column 0 has ColumnName "Column1" Column 1 has ColumnName "" Column 1 has ColumnName "Column2" Column 2 has ColumnName "" Column 2 has ColumnName "Column3" Column 3 has ColumnName "" Column 3 has ColumnName "Column4" Column 4 has ColumnName "" Column 4 has ColumnName "Column5"
...因此您始終可以使用這些默認名稱。 此外,僅僅因為您的輸入數據未指定列/字段名稱並不意味着在將其加載到DataTable
后您不能這樣做...
DtFromExcel.Columns[1].ColumnName = "MyDateColumn";
無論哪種方式,您都會有一個已知名稱,您可以通過該名稱引用該列。
至於您關於不想“循環遍歷整個DataTable
”的評論,尚不清楚您的意思是因為附加代碼還是性能影響,但到后一點,即使您沒有明確循環並測試每個DataRow
, Select()
將. 關於這一點,由於您說行是按日期排序的,因此您可以利用LINQ在找到搜索范圍之外的日期后立即停止掃描行...
private static DateTime GetRowDate(DataRow row) => DateTime.ParseExact(
(string) row["MyDateColumn"], "MM/dd/yyyy ddd", null
);
private void DeleteRows(DateTime maxDate)
{
DataRow[] rowsToRemove = DtFromExcel.AsEnumerable()
.TakeWhile(row => GetRowDate(row) <= maxDate)
.ToArray();// Required to prevent "Collection was modified" exception in foreach below
foreach (DataRow row in rowsToRemove)
DtFromExcel.Rows.Remove(row);
}
如果您的行不能保證按日期排序,那么您可以將Where()
替換為TakeWhile()
並且它的工作方式相同。
至於您使用DateTable.Select()
的原始請求,我不確定這是否可行,因為您的日期似乎存儲為string
,而不是DateTime
,在您的DataColumn
中。 我看到表達式語法支持可以在String
和DateTime
之間轉換的CONVERT()
function ,但我無法想象它會比 LINQ 更具性能或可讀性,所以除非你絕對必須這樣做,否則我不會追求它。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.