Agrupando objetos contidos em uma Lista

Agrupamento com List < object[] > como saída

object[] é o array de objetos onde vai ser adiciona a saída do agrupamento. Neste exemplo a posição [0] (zero) vai contem a chave do grupamento, que é o type do produto e na posição [1] (um) a soma dos preços dos produtos

using System;
using System.Collections.Generic;
using System.Linq;
namespace GroupListItens
{
    class Program
    {
        static void Main(string[] args)
        {
            var productList = new List<Product>();
            productList.Add(new Product() { Id = 1, Description = "Mouse", Price = 10.1, Type = "ELECTRONIC" });
            productList.Add(new Product() { Id = 2, Description = "Coffee", Price = 5.2, Type = "FOOD" });
            productList.Add(new Product() { Id = 3, Description = "Keyboard", Price = 15.1, Type = "ELECTRONIC" });
            productList.Add(new Product() { Id = 4, Description = "Fifa", Price = 7.3, Type = "GAME" });
            productList.Add(new Product() { Id = 5, Description = "Dota", Price = 10.3, Type = "GAME" });
            productList.Add(new Product() { Id = 6, Description = "Headphone", Price = 20.1, Type = "ELECTRONIC" });
            productList.Add(new Product() { Id = 7, Description = "Mouse pad", Price = 2.1, Type = "ELECTRONIC" });
            
            List<object[]> newList = productList
                .GroupBy(_ => _.Type)
                .Select(_ => new object[]
                {
                    _.Key,
                    _.Sum(x => (double) x.Price)
                })
                .ToList();

            PrintListObject(newList);
        }
        public static void PrintListObject(List<object[]> productList)
        {
            foreach (var item in productList)
            {
                Console.WriteLine(item[0] + " - " + item[1]);
            }
        }
    }
    public class Product
    {
        public int Id { get; set; }
        public string Description { get; set; }
        public double Price { get; set; }
        public string Type { get; set; }
    }
}
/* Program exit
ELECTRONIC - 47.4
FOOD - 5.2
GAME - 17.6
Press any key to continue . . .
*/

Agrupamento com List < GroupProduct > como saída

GroupProduct é a classe que contem os atribuitos usandos no agrupamento. Este objeto é criado e populado no .select da expressão LINQ.

using System;
using System.Collections.Generic;
using System.Linq;
namespace GroupListItens
{
    class Program
    {
        static void Main(string[] args)
        {
            var productList = new List<Product>();
            productList.Add(new Product() { Id = 1, Description = "Mouse", Price = 10.1, Type = "ELECTRONIC" });
            productList.Add(new Product() { Id = 2, Description = "Coffee", Price = 5.2, Type = "FOOD" });
            productList.Add(new Product() { Id = 3, Description = "Keyboard", Price = 15.1, Type = "ELECTRONIC" });
            productList.Add(new Product() { Id = 4, Description = "Fifa", Price = 7.3, Type = "GAME" });
            productList.Add(new Product() { Id = 5, Description = "Dota", Price = 10.3, Type = "GAME" });
            productList.Add(new Product() { Id = 6, Description = "Headphone", Price = 20.1, Type = "ELECTRONIC" });
            productList.Add(new Product() { Id = 7, Description = "Mouse pad", Price = 2.1, Type = "ELECTRONIC" });
            
            List<GroupProduct> GroupProduct = productList
                .GroupBy(_ => _.Type)
                .Select(_ => new GroupProduct()
                {
                    Type = _.Key,
                    SumPrice = _.Sum(x => (double) x.Price)
                })
                .ToList();

            PrintListGroupProduct(GroupProduct);
        }
        public static void PrintListGroupProduct(List<GroupProduct> productList)
        {
            foreach (var item in productList)
            {
                Console.WriteLine(item.Type + " - " + item.SumPrice);
            }
        }
    }
    public class Product
    {
        public int Id { get; set; }
        public string Description { get; set; }
        public double Price { get; set; }
        public string Type { get; set; }
    }
    public class GroupProduct
    {
        public double SumPrice { get; set; }
        public string Type { get; set; }
    }
}

Agrupamento com List < ExpandoObject > como saída

ExpandoObject Representa um objeto cujos membros podem ser dinamicamente adicionados e removidos no tempo de execução. Este objeto é criado e populado no .select da expressão LINQ.

using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq;
namespace GroupListItens
{
    class Program
    {
        static void Main(string[] args)
        {
            var productList = new List<Product>();
            productList.Add(new Product() { Id = 1, Description = "Mouse", Price = 10.1, Type = "ELECTRONIC" });
            productList.Add(new Product() { Id = 2, Description = "Coffee", Price = 5.2, Type = "FOOD" });
            productList.Add(new Product() { Id = 3, Description = "Keyboard", Price = 15.1, Type = "ELECTRONIC" });
            productList.Add(new Product() { Id = 4, Description = "Fifa", Price = 7.3, Type = "GAME" });
            productList.Add(new Product() { Id = 5, Description = "Dota", Price = 10.3, Type = "GAME" });
            productList.Add(new Product() { Id = 6, Description = "Headphone", Price = 20.1, Type = "ELECTRONIC" });
            productList.Add(new Product() { Id = 7, Description = "Mouse pad", Price = 2.1, Type = "ELECTRONIC" });

            List<ExpandoObject> groupProduct = productList
                .GroupBy(_ => _.Type)
                .Select(_ => 
                {
                    dynamic expando = new ExpandoObject();
                    expando.Type = _.Key;
                    expando.SumPrice = _.Sum(x => x.Price);
                    return (ExpandoObject) expando;
                })
                .ToList();

            PrintListExpandoObject(groupProduct);
        }

        public static void PrintListExpandoObject(List<ExpandoObject> groupProduct)
        {
            foreach (var item in groupProduct)
            {
                var itemType = (item.FirstOrDefault(c => c.Key == "Type").Value ?? string.Empty).ToString();
                var itemSumPrice = (item.FirstOrDefault(c => c.Key == "SumPrice").Value ?? string.Empty).ToString();
                Console.WriteLine(itemType + " - " + itemSumPrice);
            }
        }
    }
    public class Product
    {
        public int Id { get; set; }
        public string Description { get; set; }
        public double Price { get; set; }
        public string Type { get; set; }
    }
}

Agrupamento com Anonymous Type como saída

Anonymous Type encapsulam um conjunto de propriedades somente leitura em um único objeto sem a necessidade de primeiro definir explicitamente um tipo.

using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq;
namespace GroupListItens
{
    class Program
    {
        static void Main(string[] args)
        {
            var productList = new List<Product>();
            productList.Add(new Product() { Id = 1, Description = "Mouse", Price = 10.1, Type = "ELECTRONIC" });
            productList.Add(new Product() { Id = 2, Description = "Coffee", Price = 5.2, Type = "FOOD" });
            productList.Add(new Product() { Id = 3, Description = "Keyboard", Price = 15.1, Type = "ELECTRONIC" });
            productList.Add(new Product() { Id = 4, Description = "Fifa", Price = 7.3, Type = "GAME" });
            productList.Add(new Product() { Id = 5, Description = "Dota", Price = 10.3, Type = "GAME" });
            productList.Add(new Product() { Id = 6, Description = "Headphone", Price = 20.1, Type = "ELECTRONIC" });
            productList.Add(new Product() { Id = 7, Description = "Mouse pad", Price = 2.1, Type = "ELECTRONIC" });

            var groupProduct = productList
                .GroupBy(_ => _.Type)
                .Select(_ => new 
                {
                    Type = _.Key,
                    SumPrice = _.Sum(x => x.Price)   
                })
                .ToList();

            foreach (var item in groupProduct)
            {
                Console.WriteLine(item.Type + " - " + item.SumPrice);
            }
        }
    }
    public class Product
    {
        public int Id { get; set; }
        public string Description { get; set; }
        public double Price { get; set; }
        public string Type { get; set; }
    }
}

Codigo completo para referenca e comparação.

using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq;
namespace GroupListItens
{
    class Program
    {
        static void Main(string[] args)
        {
            var productList = new List<Product>();
            productList.Add(new Product() { Id = 1, Description = "Mouse", Price = 10.1, Type = "ELECTRONIC" });
            productList.Add(new Product() { Id = 2, Description = "Coffee", Price = 5.2, Type = "FOOD" });
            productList.Add(new Product() { Id = 3, Description = "Keyboard", Price = 15.1, Type = "ELECTRONIC" });
            productList.Add(new Product() { Id = 4, Description = "Fifa", Price = 7.3, Type = "GAME" });
            productList.Add(new Product() { Id = 5, Description = "Dota", Price = 10.3, Type = "GAME" });
            productList.Add(new Product() { Id = 6, Description = "Headphone", Price = 20.1, Type = "ELECTRONIC" });
            productList.Add(new Product() { Id = 7, Description = "Mouse pad", Price = 2.1, Type = "ELECTRONIC" });

            List<object[]> newList = productList
                .GroupBy(_ => _.Type)
                .Select(_ => new object[]
                {
                    _.Key,
                    _.Sum(x => (double) x.Price)
                })
                .ToList();

            PrintListObject(newList);

            List<GroupProduct> GroupProduct = productList
                .GroupBy(_ => _.Type)
                .Select(_ => new GroupProduct()
                {
                    Type = _.Key,
                    SumPrice = _.Sum(x => (double)x.Price)
                })
                .ToList();

            PrintListGroupProduct(GroupProduct);

            List<ExpandoObject> groupProduct = productList
                .GroupBy(_ => _.Type)
                .Select(_ =>
                {
                    dynamic expando = new ExpandoObject();
                    expando.Type = _.Key;
                    expando.SumPrice = _.Sum(x => x.Price);
                    return (ExpandoObject)expando;
                })
                .ToList();

            PrintListExpandoObject(groupProduct);

            var groupProductVar = productList
                .GroupBy(_ => _.Type)
                .Select(_ => new
                {
                    Type = _.Key,
                    SumPrice = _.Sum(x => x.Price)
                })
                .ToList();

            foreach (var item in groupProductVar)
            {
                Console.WriteLine(item.Type + " - " + item.SumPrice);
            }
        }

        public static void PrintListExpandoObject(List<ExpandoObject> groupProduct)
        {
            foreach (var item in groupProduct)
            {
                var itemType = (item.FirstOrDefault(c => c.Key == "Type").Value ?? string.Empty).ToString();
                var itemSumPrice = (item.FirstOrDefault(c => c.Key == "SumPrice").Value ?? string.Empty).ToString();
                Console.WriteLine(itemType + " - " + itemSumPrice);
            }
        }

        public static void PrintListGroupProduct(List<GroupProduct> productList)
        {
            foreach (var item in productList)
            {
                Console.WriteLine(item.Type + " - " + item.SumPrice);
            }
        }

        public static void PrintListObject(List<object[]> productList)
        {
            foreach (var item in productList)
            {
                Console.WriteLine(item[0] + " - " + item[1]);
            }
        }
    }

    public class Product
    {
        public int Id { get; set; }
        public string Description { get; set; }
        public double Price { get; set; }
        public string Type { get; set; }
    }

    public class GroupProduct
    {
        public double SumPrice { get; set; }
        public string Type { get; set; }
    }
}

Qualquer dúvida ou dicas, entre em contato: leandrolt@gmail.com

Principais referências

https://stackoverflow.com/questions/13962393/group-and-sum-a-listobject
https://stackoverflow.com/questions/9259570/is-it-possible-to-create-properties-on-the-fly-with-a-net-dynamic-object
https://stackoverflow.com/questions/15554917/using-linq-is-it-possible-to-output-a-dynamic-object-from-a-select-statement-i
https://www.tutorialsteacher.com/csharp/csharp-anonymous-type
https://docs.microsoft.com/pt-br/dotnet/api/system.dynamic.expandoobject?view=netframework-4.8
https://stackoverflow.com/questions/2327594/declaration-of-anonymous-types-list

Leave a Reply

Your email address will not be published. Required fields are marked *