Список разделов LINQ в списки из 8 членов

Как взять List (используя LINQ) и разбить его на список списков, разделяющих исходный список на каждую восьмую запись?

Я предполагаю, что что-то вроде этого будет включать Skip и / или Take, но я все еще довольно новичок в LINQ.

Изменить: использование C # / .Net 3.5

Edit2: Этот вопрос сформулирован иначе, чем другой «дублирующий» вопрос. Хотя проблемы схожи, ответы в этом вопросе превосходят: «принятый» ответ очень твердый (с утверждением yield ), а также предложение Джона Скита использовать MoreLinq (что не рекомендуется в «другом» вопросе. ) Иногда дубликаты хороши тем, что они заставляют пересмотреть проблему.

Используйте следующий метод расширения, чтобы разбить вход на подмножества

 public static class IEnumerableExtensions { public static IEnumerable> InSetsOf(this IEnumerable source, int max) { List toReturn = new List(max); foreach(var item in source) { toReturn.Add(item); if (toReturn.Count == max) { yield return toReturn; toReturn = new List(max); } } if (toReturn.Any()) { yield return toReturn; } } } 

У нас есть только такой метод в MoreLINQ как метод пакетной обработки :

 // As IEnumerable> var items = list.Batch(8); 

или

 // As IEnumerable> var items = list.Batch(8, seq => seq.ToList()); 

Вам лучше использовать библиотеку, такую ​​как MoreLinq , но если вам действительно нужно было это сделать, используя «простой LINQ», вы можете использовать GroupBy :

 var sequence = new[] {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16}; var result = sequence.Select((x, i) => new {Group = i/8, Value = x}) .GroupBy(item => item.Group, g => g.Value) .Select(g => g.Where(x => true)); // result is: { {1,2,3,4,5,6,7,8}, {9,10,11,12,13,14,15,16} } 

В принципе, мы используем версию Select() которая предоставляет индекс для потребляемого значения, мы делим индекс на 8, чтобы определить, к какой группе принадлежит каждое значение. Затем мы группируем последовательность с помощью этого ключа группировки. Последний Select просто уменьшает IGrouping<> вниз до IEnumerable> (и не является абсолютно необходимым, поскольку IGrouping является IEnumerable ).

Достаточно легко превратить это в метод многократного использования путем факторизации нашей константы 8 в примере и замены ее на указанный параметр. Это не обязательно самое элегантное решение, и это уже не ленивое, streamовое решение … но оно действительно работает.

Вы также можете написать свой собственный метод расширения с использованием блоков iteratorа ( yield return ), которые могут дать вам лучшую производительность и использовать меньше памяти, чем GroupBy . Это то, что Batch() метод MoreLinq делает IIRC.

Это совсем не то, что имели в виду первоначальные дизайнеры Linq, но проверьте это злоупотребление GroupBy:

 public static IEnumerable> BatchBy(this IEnumerable items, int batchSize) { var count = 0; return items.GroupBy(x => (count++ / batchSize)).ToList(); } [TestMethod] public void BatchBy_breaks_a_list_into_chunks() { var values = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; var batches = values.BatchBy(3); batches.Count().ShouldEqual(4); batches.First().Count().ShouldEqual(3); batches.Last().Count().ShouldEqual(1); } 

Я думаю, что он выигрывает премию «гольф» за этот вопрос. ToList очень важен, так как вы хотите убедиться, что группировка действительно была выполнена до того, как вы попытаетесь что-либо сделать с выходом. Если вы удалите ToList , вы получите некоторые странные побочные эффекты.

Take не будет очень эффективным, потому что он не удаляет сделанные записи.

почему бы не использовать простой цикл:

 public IEnumerable> Partition(this/* <-- see extension methods*/ IEnumerable src,int num) { IEnumerator enu=src.getEnumerator(); while(true) { List result=new List(num); for(int i=0;i0)yield return result; yield break; } result.Add(enu.Current); } yield return result; } } в public IEnumerable> Partition(this/* <-- see extension methods*/ IEnumerable src,int num) { IEnumerator enu=src.getEnumerator(); while(true) { List result=new List(num); for(int i=0;i0)yield return result; yield break; } result.Add(enu.Current); } yield return result; } } 
 from b in Enumerable.Range(0,8) select items.Where((x,i) => (i % 8) == b); 

Самое простое решение дано Мелом:

 public static IEnumerable> Partition(this IEnumerable items, int partitionSize) { int i = 0; return items.GroupBy(x => i++ / partitionSize).ToArray(); } 

Кратко, но медленнее. Вышеупомянутый метод разбивает IEnumerable на куски требуемого фиксированного размера, при этом общее количество кусков не имеет значения. Чтобы разбить IEnumerable на N количество блоков равных размеров или близких к равным, вы можете сделать:

 public static IEnumerable> Split(this IEnumerable items, int numOfParts) { int i = 0; return items.GroupBy(x => i++ % numOfParts); } 

Чтобы ускорить работу, простой подход:

 public static IEnumerable> Partition(this IEnumerable items, int partitionSize) { if (partitionSize <= 0) throw new ArgumentOutOfRangeException("partitionSize"); int innerListCounter = 0; int numberOfPackets = 0; foreach (var item in items) { innerListCounter++; if (innerListCounter == partitionSize) { yield return items.Skip(numberOfPackets * partitionSize).Take(partitionSize); innerListCounter = 0; numberOfPackets++; } } if (innerListCounter > 0) yield return items.Skip(numberOfPackets * partitionSize); } 

Это быстрее, чем что-либо в настоящее время на планете сейчас 🙂 Эквивалентные методы для операции Split здесь

  • LINQ Group по нескольким полям -Syntax help
  • Сортировка списка на основе другого списка
  • Что такое эквивалент Java для LINQ?
  • Экспорт модели в DataTable
  • Как быстро удалить элементы из списка
  • LINQ: Строка строки Entity содержит любой массив строк
  • Почему LINQ to Entities не распознает метод «System.String ToString ()?
  • Как выполнить подзапрос в LINQ?
  • C #: Как преобразовать список объектов в список одного свойства этого объекта?
  • Проверьте, равны ли два списка
  • Сохранение заказа с помощью LINQ
  • Interesting Posts

    Могу ли я получить аргументы командной строки других процессов из .NET / C #?

    Текстовая тень в Internet Explorer?

    Формы, не отвечающие на события KeyDown

    ClearCase хочет объединить неизменные файлы после доставки в альтернативную цель

    Как удалить запись MySQL через определенное время

    Стеганографическое программное обеспечение

    Сохранять историю команд cmd.exe между сеансами?

    Для моего собственного DNS-сервера «dig … @ ip-address» работает, но «dig … @domainname» не

    Запуск пользовательской задачи автоматически до / после стандартной задачи

    Создание кросс-платформенного приложения Java SWT

    Как я могу выйти из Skype со всего входа в мою учетную запись?

    Как проверить, существует ли файл в приложении Windows Store?

    пример подключения / отмены привязки (android)

    MATLAB: применить фильтр низких частот или верхних частот к массиву

    Выбор значений атрибутов с помощью html Agility Pack

    Давайте будем гением компьютера.