Использовать 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;
}