2015-02-02 3 views
-4

У меня есть список строк, иногда более 10.000.000 строк в списке.C# цикл через множество элементов в списке

Мне нужно прокрутить список и отправить куски этих данных в API, подсписок из 2k строк для каждого API-вызова.

Что было бы самым эффективным способом сделать это?

+3

Есть ли у вас что полный список в памяти, в буквальном смысле, как '' List ? Можете ли вы просто использовать индексы? что ты уже испробовал? (В отличие от предыдущей версии этого комментария, похоже, что LINQ to Objects делает * not * optimize Skip, поэтому повторное использование Skip/Take будет медленным. Существуют различные другие LINQ-связанные параметры, хотя ...) –

ответ

2

Используйте LINQ Take и Skip оператором мудро с переменными.

Например, синтаксис будет что-то вроде ценам ниже

IEnumerable<resultStrings> page1 = myStrings.Skip(0).Take(2000);    
IEnumerable<resultStrings> page2 = myStrings.Skip(2000).Take(2000); 
+0

С 10 миллионами Это очень медленно. –

+0

Согласен. Но это первый вопрос, пока не будет развита более подробная информация по вопросу :-) – Amit

1

Попробуйте метод GetRange:

 List<int> list = new List<int>() { 1, 2, 3, 4, 5}; 

     var chunk = 2; 
     var iterations = list.Count/chunk; 

     for (int i = 0; i < iterations; i++) 
     { 
      var portion = list.GetRange(chunk * i, chunk); 
      //Do API 
     } 

     var remainder = list.GetRange(chunk * iterations, list.Count - chunk * iterations); 
     //Do API 

Вы можете посмотреть на какой-то эталонный тест на GetRange против Take, где выигрывает GetRange. https://icodeit.wordpress.com/2012/08/27/performance-of-skip-and-take-in-linq-to-objects/

+0

Но 'GetRange' нужно создавать новые списки в памяти снова и снова, в то время как' Skip'/'Take' просто нужен процессор и нет дополнительной памяти. ОП должен решить, что более важно. –

+0

++ Но в большинстве случаев это должен быть самый эффективный и прямой подход. –

+0

Да, но если есть список ссылочных типов, потребление памяти будет не таким большим, я думаю –

0

Вероятно, наиболее эффективным подходом является использование базы данных вместо загрузки всех в памяти (из любого места), а затем использовать Skip/Take принять ее части.

Однако, вы можете использовать GroupBy:

var chunks = largeStringList.Select((str, index) => new { str, index }) 
    .GroupBy(x => x.index/2000, x => x.str); 
foreach (var chunkGroup in chunks) 
    Console.WriteLine(String.Join(",", chunkGroup)); 

Я запустить небольшой тест производительности с этим результатом:

List.GetRange:

00:00:00.0404119 (40 milliseconds) 

(мой) GroupBy:

00:00:02.2386504 (two seconds) 

Skip/Take:

00:10:11.6467726 (yes, more than 10 minutes) 
Смежные вопросы