views:

22

answers:

1

Hi,

Suppose 2 classes, Person and Pet. Each person has a collection of 1 or more pets. How do i group the Person in to a collection where they share the same pets.

Example:

Person 1: Cat, Dog, Spider

Person 2: Cat, Spider, Snake

Person 3: Dog

Person 4: Spider, Cat, Dog

Person 5: Dog

What i want as a result is this:

Group 1: Person 1, Person 4

Group 2: Person 3, Person 5

Group 3: Person 2

How do i achieve this using LINQ?

+1  A: 

One way is to build a comparable key out of the pets. For example, this method sorts the pets then combines them into a single string separated by '|'

private static string GetPetKey(Person x)
{
    return String.Join("|", x.Pets.OrderBy(y => y).ToArray());
}

A person with the pets: "Spider", "Cat", "Dog" gets the key: "Cat|Dog|Spider"

Then use that as your LINQ grouping key

var grouped = people.GroupBy(x => GetPetKey(x))

sample implementation:

var people = new List<Person>
    {
        new Person
            {
                Id = 1,
                Pets = new[] { "Cat", "Dog", "Spider" }
            },
        new Person
            {
                Id = 2,
                Pets = new[] { "Cat", "Spider", "Snake" }
            },
        new Person
            {
                Id = 3,
                Pets = new[] { "Dog" }
            },
        new Person
            {
                Id = 4,
                Pets = new[] { "Spider", "Cat", "Dog"  }
            },
        new Person
            {
                Id = 5,
                Pets = new[] { "Dog" }
            }
    };

var grouped = people.GroupBy(x => GetPetKey(x)).ToList();
grouped.ForEach(WriteGroup);

output helper

private static void WriteGroup(IGrouping<string, Person> grouping)
{
    Console.Write("People with " +String.Join(", ",grouping.First().Pets)+": ");
    var people = grouping.Select(x=>"Person "+x.Id).ToArray();
    Console.WriteLine(String.Join(", ", people));
}

output:

People with Cat, Dog, Spider: Person 1, Person 4
People with Cat, Spider, Snake: Person 2
People with Dog: Person 3, Person 5
Handcraftsman
Thanks. It was the only solution i could think of myself. It's not the pretiest but i think i will go for this now.
Jeroen
Seems nobody else can come up with a better answer, so i marked the only reply ans the correct answer.
Jeroen