Dog Sort

Dog Sort

You've heard of bubble sort and insertion sort and all the other sorts of sorts. But what about sorting and grouping your favourite dogs?

I was experimenting with the IEnumerable.GroupBy function and was trying to come up with an abstract (non-work related), yet understandable example. And who doesn't like dogs? So I thought, what if we had an arbitrary list of dogs that we identify by name, breed and age.


public class Dog
{
    public string Name { get; set; }
    public int Age { get; set; }
    public string Breed { get; set; }
}

and a list of dogs at random...


var dogs = new List<Dog>{ 
            new Dog { Name="Barley",   Age=8, Breed="Mongoose" },
            new Dog { Name="Farley",   Age=8, Breed="Mongoose" },
            new Dog { Name="Marley",   Age=8, Breed="Alsation" },
            new Dog { Name="Carley",   Age=8, Breed="Border Terrier" },
            new Dog { Name="Boots",    Age=4, Breed="Border Terrier" },
            new Dog { Name="Whiskers", Age=1, Breed="Scotty" },
            new Dog { Name="Daisy",    Age=4, Breed="Spaniel" } };

Is there a way to group them into sets according to whatever criteria need. Ordinarily, I've seen code where we create one list per grouping then for-each around the list of dogs, select using the criteria and add to whichever list. This isn't very scalable since you have to create one list per grouping ahead of time and manage the complication of deciding which list we add each item into.

GroupBy gives us a better way to manage that complexity without the need for managing lists by hand. First, we need a way to compare items in the list. We do this with a custom type I've called DogKey.


public class DogKey
{
    public int Age { get; set; }
    public string Breed { get; set; }
}

We also need a way to compare each item based on that key. So we implement an IEqualityComparer for the key. The selection criteria are down to us so here I'm comparing based on breed but it could be age, name or any combination. Any two items that match according to the comparision will be placed into the same group.


public class GroupByBreed : IEqualityComparer<DogKey>
{
    public bool Equals(DogKey x, DogKey y)
    {
        return x.Breed.CompareTo(y.Breed) == 0;
    }

    public int GetHashCode(DogKey obj)
    {
        return 0;
    }
}

public class GroupByAge : IEqualityComparer<DogKey>
{
    public bool Equals(DogKey x, DogKey y)
    {
        return x.Age == y.Age;
    }

    public int GetHashCode(DogKey obj)
    {
        return 0;
    }
}

Then actually implementing the grouping comes out into a single function call. We can then print out the results


IEnumerable<IGrouping<DogKey, Dog>> query = dogs.GroupBy(pet => 
    new DogKey { Age = pet.Age, Breed = pet.Breed }, 
    new GroupByBreed());

foreach (IGrouping<DogKey, Dog> petGroup in query)
{
    Console.WriteLine("\t{0}", petGroup.Key.Breed);
    Console.WriteLine("\t-------------------------");

    foreach (Dog pet in petGroup)
        Console.WriteLine("\t\t{0}", pet.Name);

    Console.WriteLine();
}

results