开发者

Use linq to break up list<t> into lots of list<t> of n length? [duplicate]

This question already has answers here: Closed 11 years ago.

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;
    }
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜