Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Linq - group a list into pairs based on a property

Tags:

c#

linq

I have a list of objects with a property that can be used to partition the objects into pairs. I know in advance that each object is part of a pair.

Here is an example to illustrate the situation:


I have a list of individual shoes that I would like to group into pairs.

Let's say my list is as follows:

List<Shoe> shoes = new List<Shoe>();

shoes.Add(new Shoe { Id = 19, Brand = "Nike", LeftOrRight = LeftOrRight.L });
shoes.Add(new Shoe { Id = 29, Brand = "Nike", LeftOrRight = LeftOrRight.R });
shoes.Add(new Shoe { Id = 11, Brand = "Nike", LeftOrRight = LeftOrRight.L });
shoes.Add(new Shoe { Id = 60, Brand = "Nike", LeftOrRight = LeftOrRight.R });
shoes.Add(new Shoe { Id = 65, Brand = "Asics", LeftOrRight = LeftOrRight.L });
shoes.Add(new Shoe { Id = 82, Brand = "Asics", LeftOrRight = LeftOrRight.R });

I would like to output these shoes as pairs, like so:

Pair:
Id: 19, Brand: Nike, LeftOrRight: L
Id: 29, Brand: Nike, LeftOrRight: R

Pair:
Id: 11, Brand: Nike, LeftOrRight: L
Id: 60, Brand: Nike, LeftOrRight: R

Pair:
Id: 65, Brand: Asics, LeftOrRight: L
Id: 82, Brand: Asics, LeftOrRight: R

Note that an individual shoe can only exist as part of a single pair.

I have tried the following code to group the shoes, but it is clearly missing the pairs:

var pairsByBrand = shoes.GroupBy(s => s.Brand);
foreach (var group in pairsByBrand)
{
    Console.WriteLine("Pair:");
    foreach (var shoe in group)
    {
        Console.WriteLine(shoe);
    }
    Console.WriteLine();
}

What statements can be used to group these items into pairs?

like image 394
Ryan Kohn Avatar asked Sep 07 '12 15:09

Ryan Kohn


1 Answers

Pure functional LINQ, using SelectMany and Zip, yielding an IEnumerable of Tuples:

IEnumerable<Tuple<Shoe, Shoe>> pairs = shoes
    .GroupBy(shoe => shoe.Brand)
    .SelectMany(brand=>
        Enumerable.Zip(
            brand.Where(shoe=>shoe.LeftOrRight == LeftOrRight.L),
            brand.Where(shoe=>shoe.LeftOrRight == LeftOrRight.R),
            Tuple.Create
        )
    );
like image 63
Thom Smith Avatar answered Sep 29 '22 20:09

Thom Smith