7

我有一个对象列表,该列表具有可用于将对象分成对的属性。我事先知道每个对象都是一对的一部分。

下面是一个例子来说明这种情况:


我有一个单鞋清单,我想把它们分成几双。

假设我的清单如下:

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 });

我想将这些鞋子成对输出,如下所示:

一对:
ID:19,品牌:耐克,左或右:L
ID:29,品牌:耐克,左或右:R

一对:
ID:11,品牌:耐克,左或右:L
ID:60,品牌:耐克,左或右:R

一对:
ID:65,品牌:Asics,左或右:L
ID:82,品牌:Asics,左或右:R

请注意,单只鞋只能作为单双的一部分存在。

我尝试使用以下代码对鞋子进行分组,但显然缺少配对:

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();
}

可以使用哪些语句将这些项目分组?

4

3 回答 3

9

纯函数 LINQ,使用SelectManyand Zip,产生一个IEnumerables Tuple

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
        )
    );
于 2012-09-07T15:20:57.693 回答
3
var shoesByBrand = shoes.GroupBy(s => s.Brand);
foreach (var byBrand in shoesByBrand)
{
    var lefts = byBrand.Where(s => s.LeftOrRight == LeftOrRight.L);
    var rights = byBrand.Where(s => s.LeftOrRight == LeftOrRight.R);
    var pairs = lefts.Zip(rights,(l, r) => new {Left = l, Right = r});

    foreach(var p in pairs)
    {
        Console.WriteLine("Pair:  {{{0}, {1}}}", p.Left.Id, p.Right.Id);
    }

    Console.WriteLine();
}

注意:Zip 只会尽可能多地配对。如果您有额外的权利或权利,他们将不会被举报。

于 2012-09-07T15:13:53.910 回答
2

一种方法:

var pairs = shoes.GroupBy(s => s.Brand)
                 .Select(g => g.GroupBy(s => s.LeftOrRight));
                 .SelectMany(Enumerable.Zip(g => g.First(), g => g.Last(),Tuple.Create));

这可能是对我最初想法(由 Thom Smith 很好地实现)的改进,因为对于每个品牌的鞋子,它通过仅迭代一次集合将它们分成左右鞋子。直觉说如果有很多鞋子的品牌应该会更快。

它的作用是按品牌对鞋子进行分组,然后在每个品牌内按左/右分组。然后它继续随机匹配每个品牌的左鞋和右鞋,依次为所有品牌匹配。

于 2012-09-07T15:23:49.823 回答