Использовать linq для разбивки списка <t> на множество списков <t> n длины?

Возможный дубликат:
Как разбить IEnumerable <String> в группы IEnumerable <string>

У меня есть список, который я бы хотел разбить на группы по 10.

Если у меня есть объект

List<Person> allPendingPersons 

который имеет длину m.

Есть ли элегантный способ в LINQ разбивать allPendingPersons на один или несколько объектов List, у которых есть до 10 человек?

Ответ 1

 var groups = allPendingPersons.Select((p, index) => new {p,index})
                               .GroupBy(a =>a.index/10 );

если вы хотите обработать IGrouping<,>. Если вы ищете List > back, вы можете попробовать

var listOfLists = allPendingPersons.Select((p, index) => new {p, index})
    .GroupBy(a => a.index/10)
    .Select((grp => grp.Select(g => g.p).ToList()))
    .ToList();

Ответ 2

Вы можете написать свой собственный метод расширения:

public static IEnumerable<IEnumerable<T>> Partition<T>(this IEnumerable<T> sequence, int size) {
    List<T> partition = new List<T>(size);
    foreach(var item in sequence) {
        partition.Add(item);
        if (partition.Count == size) {
            yield return partition;
            partition = new List<T>(size);
        }
    }
    if (partition.Count > 0)
        yield return partition;
}

I исследовал это более подробно в своем блоге.

Ответ 3

Reactive Extensions for.NET(Rx) имеет метод расширения, который делает именно то, что вы хотите:

var buffered = allPendingPersons.BufferWithCount(10);

Если вы хотите сделать это с помощью LINQ, вы можете сделать это:

var buffered =
    allPendingPersons
        .Select((p, i) => new { Group = i / 10, Person = p })
        .GroupBy(x => x.Group, x => x.Person)
        .Select(g => g.ToArray());

Ответ 4

Это должно помочь.

Как я могу разделить IEnumerable <String> в группы IEnumerable <string>
Разделите большой IEnumerable на меньший IEnumerable на количество исправлений элемента
Могу ли я улучшить эти методы расширения Pagination?
Получить группы из 4 элементов из списка значений значений с помощью LINQ в С#
LINQ: Получите минимальные и максимальные значения последовательности чисел, разделенных на подпоследовательности
Список разделов LINQ в списки из 8 участников

Один очень популярный ответ - проверить Jon Skeet MoreLinq, в частности, функцию Batch, которая не только что вы просите, но также позволяет указать селектор возврата!

Ответ 5

Это не самый эффективный метод, но это приведет к последовательности IEnumerable<IEnumerable<Person>>, причем каждая внутренняя последовательность содержит десять элементов:

var query = allPendingPersons.Select((x, i) => new { Value = x, Group = i / 10 })
                             .GroupBy(x => x.Group,
                                      (k, g) => g.Select(x => x.Value));

И если результат действительно должен быть списком списков, а не простой последовательностью, вы можете создать List<List<Person>> вместо этого, добавив несколько вызовов ToList:

var query = allPendingPersons.Select((x, i) => new { Value = x, Group = i / 10 })
                             .GroupBy(x => x.Group,
                                      (k, g) => g.Select(x => x.Value).ToList())
                             .ToList();

Ответ 6

Попробуйте блок итератора:

public static IEnumerable<List<Person>> AsGroups(this List<Person> persons)
{
    var buf = new List<Person>(10);
    for (int i = 0; i<persons.Count i++;)
    {
        buf.Add(persons[i]);
        if (i%10 == 0 && buf.Count > 0)
        {
           yield return buf;
           buf = new List<Person>(10);
        }
    }
    yield return buf;
 }

Ответ 7

В LINQ есть элегантный способ

элегантный способ не очень эффективен. Вот более эффективный способ...

    public static List<List<T>> Chunk<T>(
      this List<T> theList,
      int chunkSize
    )
    {
        if (!theList.Any())
        {
            return new List<List<T>>();
        }

        List<List<T>> result = new List<List<T>>();
        List<T> currentList = new List<T>();
        result.Add(currentList);

        int i = 0;
        foreach(T item in theList)
        {
            if (i >= chunkSize)
            {
                i = 0;
                currentList = new List<T>();
                result.Add(currentList);
            }
            i += 1;
            currentList.Add(item);
        }
        return result;
    }