C# 使用Linq组合两个列表并获得总数量

C# 使用Linq组合两个列表并获得总数量,c#,linq,C#,Linq,我有两份来自两个不同仓库的清单 var list1 = new List<Tshirt> { new Tshirt(){ Color = "blue", size="M", qty=3 }, new Tshirt(){ Color = "red", size="M", qty=2 }, new Tshirt(){ Color = "green", size="M", qty=3 }, new Tshirt(){ Color = "blue", size

我有两份来自两个不同仓库的清单

var list1 = new List<Tshirt> {
    new Tshirt(){ Color = "blue", size="M", qty=3 },
    new Tshirt(){ Color = "red", size="M", qty=2 },
    new Tshirt(){ Color = "green", size="M", qty=3 },
    new Tshirt(){ Color = "blue", size="M", qty=3 },
}

var list2 = new List<Tshirt> {
    new Tshirt(){ Color = "blue", size="M", qty=5 },
    new Tshirt(){ Color = "red", size="M", qty=7 },
}
使用LINQ,如何得到这样一个组合列表

var list3 = new List<Tshirt> {
    new Tshirt(){ Color = "blue", size="M", qty=11 },
    new Tshirt(){ Color = "red", size="M", qty=9 },
    new Tshirt(){ Color = "green", size="M", qty=3 }
}

我最初对这个问题的回答不正确,请参阅下面的第二个标题,将所有不同的Tshirt实例组合在一起,以获得我最初的、不相关的答案

要合并所有Tshirt实例并求其QTY之和,请执行以下操作: 我看到您正在使用颜色+大小的元组来唯一标识一种类型的t恤,这意味着如果我们将所有Tshirt实例组合在一起,然后按颜色+大小对它们进行分组,然后对数量值求和,然后在新列表中返回新的Tshirt实例

List<Tshirt> aggregatedShirts = uniqueShirts = Enumerable
    .Empty<Tshirt>()
    .Concat( list1 )
    .Concat( list2 )
    .GroupBy( shirt => new { shirt.Color, shirt.size } )
    .Select( grp => new Tshirt()
    {
        Color = grp.Key.Color,
        size  = grp.Key.size,
        qty   = grp.Sum( shirt => shirt.qty )
    } )
    .ToList();
如果Tshirt未实现IEquatable,则可以使用接受IEqualityComparer的Distinct重载:


我最初对这个问题的回答不正确,请参阅下面的第二个标题,将所有不同的Tshirt实例组合在一起,以获得我最初的、不相关的答案

要合并所有Tshirt实例并求其QTY之和,请执行以下操作: 我看到您正在使用颜色+大小的元组来唯一标识一种类型的t恤,这意味着如果我们将所有Tshirt实例组合在一起,然后按颜色+大小对它们进行分组,然后对数量值求和,然后在新列表中返回新的Tshirt实例

List<Tshirt> aggregatedShirts = uniqueShirts = Enumerable
    .Empty<Tshirt>()
    .Concat( list1 )
    .Concat( list2 )
    .GroupBy( shirt => new { shirt.Color, shirt.size } )
    .Select( grp => new Tshirt()
    {
        Color = grp.Key.Color,
        size  = grp.Key.size,
        qty   = grp.Sum( shirt => shirt.qty )
    } )
    .ToList();
如果Tshirt未实现IEquatable,则可以使用接受IEqualityComparer的Distinct重载:


输入列表list1和list2总共有三个中蓝色衬衫实例,输出列表list3有两个中蓝色实例,其中一些数量是组合在一起的。使用Distinct不会只产生一件中蓝色衬衫吗?@BACON Argh,你说得对!在回答问题之前,我没有完全阅读问题。@BACON我已经用OP实际问题的解决方案更新了我的答案。新代码仍然会为每个颜色/大小组合生成一个Tshirt实例。正如我对这个问题本身所评论的,我不知道,或者至少没有解释代码如何知道数量为3+3+8的中蓝色衬衫应该组合成8+3。可能没有Tshirt实例的数量>=10?或者,有两个qty=3的实例有什么特别之处,这样只有一个实例被添加到qty=8的实例中,而剩下的一个实例被添加到一个新实例中?我认为还需要更多的信息。@BACON是的,OP的问题帖子肯定是不费吹灰之力的-但我假设我的新答案就是他们想要的,因为其他任何东西都没有多大意义。输入列表list1和list2总共有三个中蓝色衬衫实例,输出列表list3有两个中蓝色实例,加上一些数量。使用Distinct不会只产生一件中蓝色衬衫吗?@BACON Argh,你说得对!在回答问题之前,我没有完全阅读问题。@BACON我已经用OP实际问题的解决方案更新了我的答案。新代码仍然会为每个颜色/大小组合生成一个Tshirt实例。正如我对这个问题本身所评论的,我不知道,或者至少没有解释代码如何知道数量为3+3+8的中蓝色衬衫应该组合成8+3。可能没有Tshirt实例的数量>=10?或者,有两个qty=3的实例有什么特别之处,这样只有一个实例被添加到qty=8的实例中,而剩下的一个实例被添加到一个新实例中?我认为还需要更多的信息。@BACON是的,OP的问题帖子肯定是不费吹灰之力的-但我假设我的新答案是他们想要的,因为其他任何东西都没有多大意义。我只是想确认一下,list3包含两个Tshirt实例,颜色=蓝色,大小=M,数量为8和3,而不是一个数量=11,这是否正确?如果是,是什么条件/逻辑导致输入列表中数量3、3和5的中蓝色Tshirt实例在输出列表中表示为8和3?另外,到目前为止,您尝试了什么来实现此功能?对不起,我的意思是按颜色和尺寸对所有衬衫进行分组,然后合并QTY。到目前为止,我尝试的是使用AddRange方法将列表2添加到列表1中。然后我创建一个list3并在list1上循环。如果列表3已经有了当前的颜色+大小组合,那么我会添加额外的数量。否则,我将使用当前项的属性在列表3中创建一个新项。虽然这看起来效率很低,但我认为LINQ更适合这种情况只是为了确认,list3包含两个Tshirt实例,颜色=蓝色,大小=M,数量为8和3,而不是一个数量=11的实例,这是否正确?如果是,是什么条件/逻辑导致输入列表中数量3、3和5的中蓝色Tshirt实例在输出列表中表示为8和3?另外,到目前为止,您尝试了什么来实现此功能?对不起,我的意思是按颜色和尺寸对所有衬衫进行分组,然后合并QTY。到目前为止,我尝试的是使用AddRange方法将列表2添加到列表1中。然后我创建一个
清单3和清单1上的循环。如果列表3已经有了当前的颜色+大小组合,那么我会添加额外的数量。否则,我将使用当前项的属性在列表3中创建一个新项。这似乎效率很低,但我认为LINQ更适合这种情况谢谢,王翔,我喜欢这个简洁的解决方案谢谢,王翔,我也喜欢这个简洁的解决方案
class TshirtComparer : IEqualityComparer<Tshirt>
{
    public static TshirtComparer Instance { get; } = new TshirtComparer();

    public Boolean Equals(Tshirt x, Tshirt y)
    {
        if( ( x == null ) != ( y == null ) ) return false;
        if( x == null ) return true;

        return x.Color == y.Color && x.size == y.size && x.qty == y.qty;
    }

    public Int32 GetHashCode(Tshirt value)
    {
        if( value == null ) return 0;
        // See https://stackoverflow.com/questions/263400/what-is-the-best-algorithm-for-an-overridden-system-object-gethashcode
        Int32 hash = 17;
        hash = hash * 23 + value.Color?.GetHashCode() ?? 0;
        hash = hash * 23 + value.size?.GetHashCode() ?? 0;
        hash = hash * 23 + value.qty;
        return hash;
    }
}
List<Tshirt> uniqueShirts = Enumerable
    .Empty<Tshirt>()
    .Concat( list1 )
    .Concat( list2 )
    .Distinct( TshirtComparer.Instance )
    .ToList();
Int32 totalQuantity = uniqueShirts.Sum( shirt => shirt.qty );
 var list3 = list1.Union(list2).GroupBy(o => new {o.Color, o.size})
                .Select(o => new Tshirt()
                {
                    Color = o.Key.Color,
                    size = o.Key.size,
                    qty = o.Sum(q => q.qty)
                }).OrderByDescending(o => o.qty).ToList();