Home > Enterprise >  Use GroupBy to make SubLists from List where the GroupBy value is a List<t>
Use GroupBy to make SubLists from List where the GroupBy value is a List<t>

Time:09-17

I have a simple List that I would like to display, grouped by which Category it is a member of. All the examples I have seen use GroupBy but with a single ID, I'm having trouble figuring out how to do so with a List. It's ok if the product appears under both Categories.

public class Product
{
    public int Id { get; set; }
    public string Title { get; set; }
    public List<Category> Categories { get; set; }
}

StringBuilder ProductList = new StringBuilder();
var p = _products.GroupBy(a => a.Categories);

foreach (var item in p)
{
    ProductList.Append($"<p><strong>{item.Key}</strong><br/>");
    foreach (var e in item)
    {
        ProductList.Append($"{e.Title}");
        ProductList.Append("</p>");
    }
}

CodePudding user response:

Here's a solution with sample data you can test yourself:

        var categories = Enumerable.Range(0, 10).Select(n => new Category { Id = n }).ToArray();
        var products = new[]
        {
            new Product { Id = 1, Title = "P1", Categories = new List<Category> { categories[0], categories[1], categories[2] } },
            new Product { Id = 2, Title = "P2", Categories = new List<Category> { categories[0], categories[1], categories[3] } },
            new Product { Id = 3, Title = "P3", Categories = new List<Category> { categories[0], categories[2], categories[3] } },
            new Product { Id = 4, Title = "P4", Categories = new List<Category> { categories[0], categories[2], categories[3] } },
            new Product { Id = 5, Title = "P5", Categories = new List<Category> { categories[0], categories[3], categories[5] } },
            new Product { Id = 6, Title = "P6", Categories = new List<Category> { categories[0], categories[4], categories[5] } },
        };

        var categoryGroups =
            from p in products
            from c in p.Categories
            group p by c.Id into g
            select g;

        foreach (var categoryGroup in categoryGroups)
        {
            Console.WriteLine($"Category {categoryGroup.Key}:");
            
            foreach (var product in categoryGroup)
            {
                Console.WriteLine($"\tProduct {product.Id}: {product.Title}");
            }

            Console.WriteLine("-----------------------------------------------------");
        }

I assume class Category has some id property, e.g. Id, to group by. If it's reference based grouping you can replace group p by c.Id into g with group p by c into g.

CodePudding user response:

You can use SelectMany to flatten the list into tuples of (Product, Category), then use GroupBy to group product by category.

StringBuilder ProductList = new StringBuilder();
var p = _products
    .SelectMany(a => a.Categories, (prod, cat) => (prod, cat))
    .GroupBy(tuple => tuple.cat, tuple => tuple.prod);

foreach (var item in p)
{
    ProductList.Append($"<p><strong>{item.Key}</strong><br/>");
    foreach (var e in item)
    {
        ProductList.Append(e.Title);
        ProductList.Append("</p>");
    }
}
  • Related