简体   繁体   English

如何从 DataTable 中删除直到某个日期的行?

[英]How do I remove rows from a DataTable up to a certain date?

I am having trouble filtering a DataTable, say DtFromExcel .我在过滤 DataTable 时遇到问题,比如DtFromExcel The DataTable does NOT have a header row, and it starts with an actual data row, and it looks something like the following. 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 | ...

The second column contains a certain date with some extra string (day of the week), and these rows are ordered by this date column.第二列包含带有一些额外字符串(星期几)的特定日期,这些行按此日期列排序。 There can be multiple rows with the same date.可以有多个具有相同日期的行。

Now, I want to delete rows where the date column contains a certain date AND any rows prior to that.现在,我想删除日期列包含某个日期的行以及之前的任何行。 For example, if the certain date is 05/04/2020 , then I need to delete all rows up to the 8th row, so that the remaining DataTable would have to look like例如,如果某个日期是05/04/2020 ,那么我需要删除第 8 行之前的所有行,以便剩余的 DataTable 看起来像

9 | 05/05/2020 Tue | DAF | AAG | ...

My problem is, first I don't know how to filter the DataTable without the column name.我的问题是,首先我不知道如何过滤没有列名的 DataTable。 I thought about assigning a header row without overwriting the first actual data row, but it seems like this is a lot of work, only to filter.我想过在不覆盖第一个实际数据行的情况下分配 header 行,但似乎这是很多工作,只是为了过滤。 Second, I am not sure how to use these conditions ((a)the second column contains a certain date, AND (b)any row with the dates prior to that certain date).其次,我不确定如何使用这些条件((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);
    }
}

I did not want to loop through the whole DataTable because this process occurs often in my program.我不想遍历整个 DataTable,因为这个过程经常发生在我的程序中。

If you use the empty constructor to create a DataColumn with no name, the documentation states...如果您使用空构造函数创建一个没有名称的DataColumn ,文档说明...

When created, a DataColumn object has no default ColumnName or Caption .创建时, DataColumn object 没有默认的ColumnNameCaption When you add it to a DataColumnCollection , a default name ( "Column1" , "Column2" , and so on) will be generated if a name has not been assigned to the ColumnName .当您将其添加到DataColumnCollection时,如果尚未为ColumnName分配名称,则将生成默认名称( "Column1""Column2"等)。

...so creating and loading a DataTable like this... ...因此创建和加载这样的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);
}

...produces this output... ...生产此 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"

...so you could always use those default names. ...因此您始终可以使用这些默认名称。 Further, just because your input data doesn't specify column/field names doesn't mean you can't do so after it's been loaded into the DataTable ...此外,仅仅因为您的输入数据未指定列/字段名称并不意味着在将其加载到DataTable后您不能这样做...

DtFromExcel.Columns[1].ColumnName = "MyDateColumn";

Either way, you'll have a known name by which you can refer to that column.无论哪种方式,您都会有一个已知名称,您可以通过该名称引用该列。

As to your comment about not wanting to "loop through the whole DataTable ", it's not clear if you mean because of the additional code or perhaps performance implications, but to the latter point even if you don't explicitly loop through and test every DataRow , Select() will .至于您关于不想“循环遍历整个DataTable ”的评论,尚不清楚您的意思是因为附加代码还是性能影响,但到后一点,即使您没有明确循环并测试每个DataRow , Select(). On that note, since you say the rows are ordered by date, you can exploit that using LINQ to stop scanning rows as soon as a date outside the search range is found...关于这一点,由于您说行是按日期排序的,因此您可以利用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);
}

If your rows aren't guaranteed to be sorted by date, then you can substitute Where() for TakeWhile() and it will work just the same.如果您的行不能保证按日期排序,那么您可以将Where()替换为TakeWhile()并且它的工作方式相同。

As for your original request to use DateTable.Select() , I'm not sure if that's even feasible here since your dates appear to be stored as string , not DateTime , in your DataColumn .至于您使用DateTable.Select()的原始请求,我不确定这是否可行,因为您的日期似乎存储为string ,而不是DateTime ,在您的DataColumn中。 I see that the expression syntax supports a CONVERT() function that can convert between String and DateTime , but I can't imagine that would be any more performant or readable than LINQ so I wouldn't pursue that unless you absolutely have to.我看到表达式语法支持可以在StringDateTime之间转换的CONVERT() function ,但我无法想象它会比 LINQ 更具性能或可读性,所以除非你绝对必须这样做,否则我不会追求它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM