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
,