簡體   English   中英

如何從 DataTable 中刪除直到某個日期的行?

[英]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 沒有默認的ColumnNameCaption 當您將其添加到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中。 我看到表達式語法支持可以在StringDateTime之間轉換的CONVERT() function ,但我無法想象它會比 LINQ 更具性能或可讀性,所以除非你絕對必須這樣做,否則我不會追求它。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM