Use linq to break up list<t> into lots of list<t> of n length? [duplicate]
Possible Duplicate:
How can I split an IEnumerable<String> into groups of IEnumerable<string>
I have a list that I would like to break into groups of 10.开发者_运维百科
If I have an object
List<Person> allPendingPersons
that is of length m.
Is there an elegant way in LINQ to break up allPendingPersons into one or more List objects that all have a up to 10 Persons?
You can write your own extension method:
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 explored this in more depth in my blog.
var groups = allPendingPersons.Select((p, index) => new {p,index})
.GroupBy(a =>a.index/10 );
if you want to process IGrouping<,>
. If you are looking for List> back you could try
var listOfLists = allPendingPersons.Select((p, index) => new {p, index})
.GroupBy(a => a.index/10)
.Select((grp => grp.Select(g => g.p).ToList()))
.ToList();
The Reactive Extensions for .NET (Rx) has an extension method that does exactly what you want:
var buffered = allPendingPersons.BufferWithCount(10);
If you want to do it using LINQ you could do this:
var buffered =
allPendingPersons
.Select((p, i) => new { Group = i / 10, Person = p })
.GroupBy(x => x.Group, x => x.Person)
.Select(g => g.ToArray());
These should be of some assistance.
How can I split an IEnumerable<String> into groups of IEnumerable<string>
Divide a large IEnumerable into smaller IEnumerable of a fix amount of item
Can I improve these Pagination extension methods?
Get groups of 4 elements from name value list using LINQ in C#
LINQ: Get min and max values of sequence of numbers divided into subsequences
LINQ Partition List into Lists of 8 members
One very popular answer is to check out Jon Skeet's MoreLinq, in particular, the Batch
function, which not only does what you are asking for, but also lets you specify a return selector!
It's not the most efficient technique, but this will produce an IEnumerable<IEnumerable<Person>>
sequence, with each inner sequence containing ten elements:
var query = allPendingPersons.Select((x, i) => new { Value = x, Group = i / 10 })
.GroupBy(x => x.Group,
(k, g) => g.Select(x => x.Value));
And if the result really does need to be a list-of-lists rather than a simple sequence then you can create a List<List<Person>>
instead by adding in a couple of ToList
calls:
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();
Try an iterator block:
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;
}
Is there an elegant way in LINQ
The elegant way is not very performant. Here is a more performant way...
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;
}
精彩评论