Wednesday, 31 May 2017

LINQ 08 Group By into

when we group our collections we can project those groupings into new elements, so for example we can take our grouping of odd and even numbers and create a new object that holds the key value, the corresponding values and their sum.

using System;
using System.Linq;

namespace pc.linq08
{
    class Program
    {
        static void Main(string[] args)
        {
            var nums = Enumerable.Range(0, 10);

            var result1 = from n in nums
                            group n by n % 2 == 0 ? "Even" : "Odd"
                            into g select new { Key = g.Key,
                                                Nums = g,
                                                Sum = g.Sum()};

            var result2 = nums.GroupBy(n => n % 2 == 0 ? "Even" : "Odd")
                .Select(g => new {Key= g.Key, Nums = g, Sum = g.Sum() });

            foreach (var g in result1) {
                Console.WriteLine($"\n\nKey: {g.Key}");
                Console.WriteLine($"Sum: {g.Sum}");
                Array.ForEach(g.Nums.ToArray(),n => Console.Write($"{n}, "));
            }
        
            foreach (var g in result2) {
                Console.WriteLine($"\n\nKey: {g.Key}");
                Console.WriteLine($"Sum: {g.Sum}");
                Array.ForEach(g.Nums.ToArray(), n => Console.Write($"{n}, "));
            }
            Console.WriteLine("\n");
        }
    }
}


now let's take a look at our people grouping example, we can group by our name lengths, use our key, and have a collection of people with that particular name length.

using System;
using System.Linq;

namespace pc.linq07
{
    class Person
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public Person(string FirstName, string LastName)
        {
            this.FirstName = FirstName;
            this.LastName = LastName;
        }
        public override string ToString()
        {
            return $"{FirstName} {LastName}";
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            var ppl = new Person[] { new Person("Pawel", "Chooch"),
                new Person("Magda", "Tyvoniuk"), new Person("Jake", "Smith"),
                new Person("Adam", "Chooch"), new Person("Pawel","Smith"),
                new Person("Tomek", "Chooch"), new Person("Adam","Smith"),
                new Person("Jake","Tyvoniuk")};

            var LastNameLengths = from p in ppl
                                  group p by GetStringLengthValue(p.LastName.Length)
                                  into g select new { Key = g.Key,
                                                      PersonCount = g.Count(),
                                                      Persons = g };

            var FirstNameLengths = ppl.GroupBy(p => GetStringLengthValue(p.FirstName.Length))
                                   .Select(g => new {Key = g.Key,
                                                     PersonCount = g.Count(),
                                                     Persons = g});

            foreach (var data in LastNameLengths) {
                Console.WriteLine($"\nLastname letter count: 
                                     {data.Key}\nPeople:{data.PersonCount}");
                Array.ForEach(data.Persons.ToArray(), 
                               p => Console.WriteLine($"\t{ p.ToString()} "));
            }

            foreach (var data in FirstNameLengths) {
                Console.WriteLine($"\nFirstname letter count: 
                                            {data.Key}\nPeople:{data.PersonCount}");
                Array.ForEach(data.Persons.ToArray(), 
                             p => Console.WriteLine($"\t{ p.ToString()} "));
            }

        }

        static string GetStringLengthValue(int l) {
            switch (l) {
                case 1: return "One";
                case 2: return "Two";
                case 3: return "Three";
                case 4: return "Four";
                case 5: return "Five";
                case 6: return "Six";
                case 7: return "Seven";
                case 8: return "Eight";
                defaultreturn "More than Eight";
            }
        }
    }
}


it's a bit of a contrived example but it's just to drive the idea of grouping and projection home