IT rekvalifikace s garancí práce. Seniorní programátoři vydělávají až 160 000 Kč/měsíc a rekvalifikace je prvním krokem. Zjisti, jak na to!
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.
Avatar
Miroslav Martíšek:18.12.2019 14:19

Ahoj, mám velice jednoduchou třídu "Customer":

sealed class Customer {
        public string Name { get; set; }
        public string Surname { get; set; }
        public DateTime DateOfBirthday { get; set; }

        public Product[] OrderedProduct { get; set; }

        ...
}

a produktu:

sealed class Product {
        public enum Category : short {
            Food = 0,
            Clothes,
            Shoes,
            HouseholdAppliance,
            PersonalItems,
            MobilPhones,
            Sport,
            Books,
            Toys,
            AdultEntertainment,
            Pets,
            Other
        };

        public string ProductName { get; set; }
        public Category ProductCategory { get; set; }
        public DateTime DateOfOrder { get; set; }
        public decimal Price { get; set; }
...
}

V programu mám vytvořenou zkušební tabulku s daty zákazníků a produktů, co si objednali:

List<Customer> customers = new List<Customer>() {
                new Customer("Jan",     "Teplý",   "1987-07-12", new Product[]{new Product("Redmi Note",       Product.Category.MobilPhones,       "2019-12-07", 5874.0M),
                                                                                    new Product("Fitness belt",     Product.Category.PersonalItems,     "2018-02-27", 1277.0M),
                                                                                    new Product("Football shoe",    Product.Category.Sport,             "2015-10-03", 1935.0M)}),

                new Customer("Zuzana",  "Malá",         "1992-11-05", new Product[]{new Product("Programming WCF",  Product.Category.Books,             "2019-12-09", 645.0M),
                                                                                    new Product("Zumo robot",       Product.Category.Toys,              "2017-06-18", 2605.0M)}),

...
}

Zkouším si na nich různé LINQ konstrukce, abych nevypadnul ze cviku :-) Jednou z nich bylo i vypsání kategorií produktů a uvedení zákazníků, kteří si objednali nějaký produkt této kategorie, například:
Sport:
Jan Teplý
Klára Bukovská
Tomáš Kudrna

Zcela mechanicky jsem sáhnul po group by a zplodil toto:

var groupProductQuery = from Customer c in customers
                                 from Product p in c.BoughtProduct
                                 group p by p.ProductCategory into ProductGroup
                                 select new {
                                     ProductID = ProductGroup.Key,
                                     CustomerList = (from Customer c in customers
                                                     from Product p in c.BoughtProduct
                                                     where p.ProductCategory == ProductGroup.Key
                                                     select new { Surname = c.Surname }).ToList()
                                 };

 Console.WriteLine("\nQuery 5 >>>");
 foreach (var gpq in groupProductQuery) {
     Console.WriteLine("Category: {0}", gpq.ProductID);
     foreach (var cust in gpq.CustomerList) {
         Console.WriteLine("  {0}", cust.Surname);
     }
 }

Funguje to, ale celé mi to přijde takové bachraté, těžkopádné, říkající si o optimalizaci ;-)
Neměl by někdo nápad, jak to přepsat do elegantnější formy?

Díky moc.

 
Odpovědět
18.12.2019 14:19
Avatar
Jakub Švasta
Lektor
Avatar
Odpovídá na Miroslav Martíšek
Jakub Švasta:19.12.2019 15:48

Tak jedna neefektivita je už v tom, že abys dostal kategorie, nejdřív procházíš zákazníky a jejich produkty. Což má ještě navíc problém, že ti ve výsledku budou chybět kategorie, ze kterých si nikdo nic neobjedná, a naopak když si toho někdo z jedné kategorie objedná víc, budeš ho tam mít víckrát. To druhé se dá obejít distinctem, ale přiznám se, že ani nevím, jak se v tomhle zápise distinct píše, a jestli to vůbec jde (StackOverflow: nejde). Osobně tohle wannabe SQL vůbec nepoužívám, řetězení metod mi přijde přehlednější a přirozenější.

Každopádně seznam kategorií by pro tebe měl být vstup. Bohužel C# neumí nativně proiterovat enum, takže se to musí obcházet pomocí statických metod GetNames nebo GetValues. GetValues je asi pocitově čistší, ale zas vrací jen negenerický Array. Takže nejlíp asi takto:

foreach (var category in Enum.GetValues(typeof(Product.Category)).Cast<Product.Category>())
{
        Console.WriteLine("Category: " + category.ToString());
        foreach (var cust in customers.Where(c => c.OrderedProduct.Select(p => p.ProductCategory).Contains(category)))
                Console.WriteLine("\t" + cust.Surname);
}

Online srovnání variant.

 
Nahoru Odpovědět
19.12.2019 15:48
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 2 zpráv z 2.