Remove Multiple Elements From List<T>

Мне было интересно, есть ли элегантный способ удалить несколько элементов из общей коллекции (в моем случае, List<T>) без выполнения каких-либо действий, таких как указание предиката в запросе LINQ для поиска удаляемых элементов?

Я делаю немного пакетной обработки, в которой я заполняю List<T> с Record типы объектов, которые должны быть обработаны. Эта обработка заканчивается каждым объектом, вставляемым в базу данных. Вместо того, чтобы создавать список, а затем циклически проходить по каждому отдельному элементу и обрабатывать / вставлять его, я хочу выполнить транзакционные массовые вставки с группами N элементы из списка, потому что это менее ресурсоемким (где N представляет BatchSize что я могу положить в файл конфигурации, или эквивалент).

Я хочу сделать что-то вроде:

public void ProcessRecords()
{
    // list of Records will be a collection of List<Record>
    var listOfRecords = GetListOfRecordsFromDb( _connectionString );
    var batchSize = Convert.ToInt32( ConfigurationManager.AppSettings["BatchSize"] );

    do
    {
       var recordSubset = listOfRecords.Take(batchSize);
       DoProcessingStuffThatHappensBeforeInsert( recordSubset );

       InsertBatchOfRecords( recordSubset );

       // now I want to remove the objects added to recordSubset from the original list
       // the size of listOfRecords afterwards should be listOfRecords.Count - batchSize
    } while( listOfRecords.Any() )
}

Я ищу способ сделать все это сразу, вместо того, чтобы перебирать подмножество и таким образом удалять элементы, такие как:

foreach(Record rec in recordSubset)
{
   if( listOfRecords.Contains(rec) ) 
   { 
      listOfRecords.Remove(rec);
   }
}

Я смотрел на использование List.RemoveRange( batchSize ), но хотел бы сначала получить некоторую обратную связь от Stackru:) Какие методы вы используете, чтобы максимизировать эффективность ваших алгоритмов пакетной обработки в C#?

Любая помощь / предложения / советы очень ценятся!

2 ответа

Решение

С методом расширения

public static IEnumerable<List<T>> ToBatches<T>(this List<T> list, int batchSize)
{
    int index = 0;
    List<T> batch = new List<T>(batchSize);

    foreach (T item in list)
    {
        batch.Add(item);    
        index++;

        if (index == batchSize)
        {
            index = 0;                
            yield return batch;
            batch = new List<T>(batchSize);
        }
    }

    yield return batch;
}

Вы можете разбить входную последовательность на партии:

foreach(var batch in listOfRecords.ToBatches(batchSize))
{
   DoProcessingStuffThatHappensBeforeInsert(batch);
   InsertBatchOfRecords(batch);
}

MoreLINQ имеет Batch метод расширения, который позволит вам позвонить

var listOfRecords = GetListOfRecordsFromDb( _connectionString );
var batchSize = Convert.ToInt32( ConfigurationManager.AppSettings["BatchSize"] );

foreach(var batch in listOfRecords.Batch(batchSize))
{
   DoProcessingStuffThatHappensBeforeInsert(batch);
   InsertBatchOfRecords(batch);
}

Вам не нужно беспокоиться о том, чтобы брать вещи из listOfRecords,

Другие вопросы по тегам