Используйте GroupBy для создания подсписков из списка, где значение GroupBy является списком

#c# #linq #group-by

Вопрос:

У меня есть простой список, который я хотел бы отобразить, сгруппированный по тому, к какой категории он относится. Во всех примерах, которые я видел, используется GroupBy, но с одним идентификатором, мне трудно понять, как это сделать со списком. Это нормально, если продукт отображается в обеих категориях.

 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>");
    }
}
 

Комментарии:

1. Вы хотите показать значения для каждой категории или для определенного набора категорий?

Ответ №1:

Вот решение с образцами данных, которые вы можете проверить самостоятельно:

         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("-----------------------------------------------------");
        }
 

Я предполагаю, что класс Category имеет некоторое свойство идентификатора , например Id , для группировки по. Если это группировка на основе ссылок, которую вы можете group p by c.Id into g заменить group p by c into g .

Ответ №2:

Вы можете использовать SelectMany для сглаживания списка в кортежи (Product, Category) , а затем использовать GroupBy для группировки товаров по категориям.

 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>");
    }
}