0

I have an list with x items. I wish to get an results that groups this list based of a number and not a property.

For example.

I have a list of 8 items. I want to group them by 3. I want to get a List thats contains three lists, where the first two lists contains each three items and the last list the remaining two.

I want a more elegant solution than this:

private static List<List<string>> GroupBy(List<string> pages, int groupSize)
{
    var result = new List<List<TrimlinePage>>();
    while (!(result.Count != 0 && result.Last().Count % 3 > 0))
    {
        int skip = result.Count*groupSize;
        var group = pages.Skip(skip).Take(groupSize).ToList();
        result.Add(group);
    }
    return result;
}

5 Answers 5

2

You can use the integer divison trick:

List<List<string>> lists = pages
    .Select((str, index) => new { str, index }) 
    .GroupBy(x => x.index / groupSize)
    .Select(g => g.Select(x => x.str).ToList())
    .ToList();

Example:

int groupSize = 3;
var pages = new List<string> { "A", "B", "C", "D", "E", "F", "G" };
List<List<string>> lists = pages
    .Select((str, index) => new { str, index })
    .GroupBy(x => x.index / groupSize)
    .Select(g => g.Select(x => x.str).ToList())
    .ToList();

Result:

foreach(var list in lists)
    Console.WriteLine(string.Join(",", list));

Output:

A,B,C
D,E,F
G

So this approach will give you lists with the specified max-size, in this case 3. If you instead want to ensure that you always get three lists you need to use % instead of /:

List<List<string>> lists = pages
    .Select((str, index) => new { str, index }) 
    .GroupBy(x => x.index % groupSize)
    .Select(g => g.Select(x => x.str).ToList())
    .ToList();
Sign up to request clarification or add additional context in comments.

Comments

0

Try this:

var list = Enumerable.Range(1,100);
var query = list
              .Select((x, i) => new {x, i})
              .GroupBy(v => v.i / 3).Select(g => g.Select(v =>v.x.ToList()))
              .ToList();

Comments

0

Here's a simple solution using side effects (which is generally discouraged):

private static List<List<string>> GroupBy(List<string> pages, int groupSize)
{
    var i = 0;
    return pages.GroupBy(p => i++ / 3, (k, g) => g.ToList()).ToList();
}

Or if you want to avoid relying on side effects, you could use this:

private static List<List<string>> GroupBy(List<string> pages, int groupSize)
{
    return pages.Select(p => new { p, i })
                .GroupBy(x => x.i / 3)
                .Select(g => g.Select(x => x.p).ToList())
                .ToList();
}

Comments

0

LINQ is not the best solution. Often good old indexing is much more readable and efficient.

private static List<List<T>> GroupBy(List<T> pages, int groupSize)
{
    var result = new List<List<T>>();
    List<T> l;
    for (int i=0; i < pages.Count; i++)
    {
        if (i%groupSize == 0)
        {
            l = new List<T>();
            result.Add(l);
        }
        l.Add(pages[i]);
    }
    return result;
}

Comments

0

You could also have a look at morelinq which contains the Partition method.

It's available via NuGet.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.