Как удалить несколько строк в DataTable?

Как я могу удалить определенные DataRows в цикле строк DataTable, которые соответствуют пользовательскому условию - скажем, строки, имеющие индекс четного числа -? (Без использования LINQ)

Спасибо


person pencilCake    schedule 26.05.2010    source источник


Ответы (10)


Это зависит от того, что вы подразумеваете под словом "удалить".

Если вы хотите пометить их как удаленные, просто вызовите метод Delete() для каждой строки, когда вы посещаете ее в своем цикле. Затем вам нужно вызвать AcceptChanges() в таблице данных, чтобы завершить удаление - предположительно после того, как вы обновите свою базу данных (если она задействована).

foreach( DataRow row in someTable.Rows )
{
    if( /* your condition here */ )
        row.Delete();
}
someTable.AcceptChanges();

Если вы имеете в виду удалить его из DataTable, вам нужно сделать это в два прохода:

List<DataRow> rowsToDelete = new List<DataRow>();
foreach( DataRow row in someTable.Rows )
{
    if( /* your condition here */ )
    {
        rowsToDelete.Add( row );
    }
}

foreach( DataRow row in rowsToDelete )
{
    someTable.Rows.Remove( row );
}

Стоит отметить, что вы всегда можете использовать первый метод для удаления строк, поскольку пометка строк как Deleted и последующее принятие изменений автоматически удалит их из таблицы. Но иногда более понятно и эффективно просто удалить объекты DataRow из коллекции Rows.

person LBushkin    schedule 26.05.2010
comment
Если вы сделаете так, как сказал Л. Бушкин, вы увидите следующее: Коллекция изменена; операция перечисления может не выполняться. так что это неправильно. - person Szjdw; 25.01.2013
comment
Пока вы вызываете .AcceptChanges() до того, как пометить строки как удаленные (до цикла foreach), вы не получите, что коллекция была изменена; операция перечисления может не выполнить ошибку. Ошибка появляется, потому что есть ожидающие изменения, которые необходимо принять. Если вы используете цикл for, это не имеет значения, но в этом случае лучше всего выполнить итерацию в обратном направлении. - person Soenhay; 22.05.2013
comment
первый метод выводит то, что сказал Szjdw, но второй работает как по волшебству, спасибо Буш! - person Albert Laure; 12.12.2013
comment
Использование Remove() не рекомендуется в цикле foreach, так как функция изменяет состояние коллекции. - person Mstislav Toivonen; 19.03.2015
comment
Второй вариант работает как шарм, первый выдаст ошибку... - person Mufaddal; 28.02.2019

Попробуйте что-то вроде этого примера

DataTable table = new DataTable();
table.Columns.Add("Foo",typeof(int));
for (int i = 0; i < 10; i++)
    table.Rows.Add(i);

for (int i = table.Rows.Count -1; i >=0; i--)
{
    // sample removes all even foos
    if ((int)table.Rows[i]["Foo"] % 2 == 0)
        table.Rows.RemoveAt(i);
}
person Anthony Pegram    schedule 26.05.2010
comment
Также можно выполнить цикл вперед (0 -> Count-1), если вы перемещаете i++ внутри цикла for и увеличиваете его только при отсутствии удаления. if (...) remove() else i++ - person CuppM; 26.05.2010

Если вам нужно более короткое решение, чем предложенное выше, попробуйте перебрать список результатов и использовать лямбду, например sub(x), чтобы удалить каждую из этих строк.

dt.Select("Column1 > 0").ToList.ForEach(Sub(x) dt.Rows.Remove(x))
person Sergey    schedule 10.08.2015

Другой способ

    DataRow[] DrArrCheck = DataTableName.Select("ID > 0");
    foreach(DataRow DrCheck in DrArrCheck)
    {
        DataTableName.Rows.Remove(DrCheck);
    }
person BharathiNathan    schedule 23.09.2010

Чтобы удалить несколько строк (например, 50 000 из 100 000), гораздо быстрее скопировать базу данных, чем выполнять datatable.Rows.Remove(row) или row.Delete(). Например:

DataRow[] rowsToKeep = datatable.Select("ID > 50000");
DataTable tempDataTable= rowsToKeep.CopyToDataTable;
dataTable.Clear();
dataTable.Merge(tempDataTable);
tempDataTable.Dispose();
person tval    schedule 01.02.2017

попробуйте перебрать результат Select(). Это очень похоже на другие ответы, но я считаю его самым прямым

DataRow[] r = table.Select();
for (int i = 0; i < r.Length; i++)
{
    if (i % 2 == 0)
        r[i].Delete();
}
person Kleinux    schedule 26.05.2010

Я всегда использовал "двухэтапный" подход Л.Бушкина и в конце концов решил, что стоит написать для него функцию:

    public delegate bool DataRowComparer(DataRow dr);

    public static void RemoveDataRows(DataTable table, DataRowComparer drc)
    {
        List<DataRow> RowsToRemove = new List<DataRow>();
        foreach (DataRow dr in table.Rows)
            if (drc(dr))
                RowsToRemove.Add(dr);
        foreach (DataRow dr in RowsToRemove)
            table.Rows.Remove(dr);
    }

И теперь я могу удалять строки одной строкой кода (например):

RemoveDataRows(dt, row => row["StringVal"].ToString() == "B" && (Int16)(row["NumberVal"]) >= 4);

В случае, если это поможет кому-то...

(И приветствуются любые способы дальнейшего сокращения.)

person user2524845    schedule 09.04.2014

Вот как я это делаю.

    for (int i = RowNumber.Count - 1; i >= 0; i--)
                        {
                            dt.Rows.RemoveAt(Int32.Parse(RowNumber[i]));
                        }

                        missingNotesGV.DataSource = dt;

                        missingNotesGV.DataBind();

Важно выполнять цикл for в обратном порядке, иначе вы получите ошибки, если будете удалять строки в конце в дополнение к строкам в других местах.

person toly P    schedule 26.05.2021

Вот как я это сделал, когда столкнулся с этой проблемой.

Dim index As Integer = 0
Dim count As Integer = resultsDT.Rows.Count - 1
For i As Integer = 0 To count
    If resultsDT.Rows(index).Item("something") = "something" Then                               
        resultsDT.Rows(index).Delete()
        resultsDT.AcceptChanges()
        index = index - 1
    End If
    index = index + 1
    i = i + 1
Next
person Jordan    schedule 06.12.2012

попробуй это

foreach(DataRow oRow in YourDataTable.Rows)
{
  if ("Check You Condition")
   {
      YourDataTable.Rows.Remove(oRow);
   }
}
person Johnny    schedule 26.05.2010
comment
Вы не можете изменить коллекцию во время итерации по ней с помощью цикла foreach. - person Ryan Rodemoyer; 18.01.2012