【问题标题】:How to get all the items in both lists even when items not existing in both lists?即使两个列表中都不存在项目,如何获取两个列表中的所有项目?
【发布时间】:2018-09-09 06:50:14
【问题描述】:

我有两个可枚举的列表。

List<List_Data> List1 = new List<List_Data>();
List1.Add(new List_Data { Material = "1", Batch = "B1", QTY = 5 });
List1.Add(new List_Data { Material = "1", Batch = "B2", QTY = 5 });
List1.Add(new List_Data { Material = "2", Batch = "B1", QTY = 15 });

List<List_Data> List2 = new List<List_Data>();
List2.Add(new List_Data { Material = "1", Batch = "B1", QTY = 2 });
List2.Add(new List_Data { Material = "3", Batch = "B1", QTY = 5 });
List2.Add(new List_Data { Material = "3", Batch = "B2", QTY = 15 });

我想要的是比较两个列表并根据材料和批次获得差异数量(list1.QTY - list2.QTY)。即使另一个列表中不存在某个项目,我也需要根据该材料和批次获得减或加数量。

这是我期待的输出。

Material = "1", Batch = "B1", QTY = 3
Material = "1", Batch = "B2", QTY = 5 
Material = "2", Batch = "B1", QTY = 15
Material = "3", Batch = "B1", QTY = -5
Material = "3", Batch = "B2", QTY = -15

这是我到目前为止所做的,

SendList = (from l1 in List1
            join l2 in List2 on new { l1.Material, l1.Batch } equals new { l2.Material, l2.Batch } into temp
            from l2 in temp.DefaultIfEmpty()
            select new Report_Class
            {
                Material = l1.Material != null ? l1.Material : l2.Material, 
                Batch = l1.Batch != null ? l1.Batch : l2.Batch, 
                Difference = l1 != null && l2 != null ? (l1.QTY - l2.QTY).ToString() : l1 != null ? l1.QTY.ToString() : l2.QTY.ToString(), 

            }).ToList();

问题是它返回 list1 所有存在的项目,但不返回仅存在于列表 2 中的项目。任何帮助将不胜感激。

谢谢。

【问题讨论】:

  • 你需要 Concat、GroupBy 和 Select
  • 错字:你的输出是QTY,但你的select语句有Difference。此外,最好使用比List1List2 更有意义的变量名。

标签: c# .net linq


【解决方案1】:

这是一种方法:

  • 反转 List2 上的 QTY
  • 将上述结果与 List1 连接起来。
  • 将串联列表按MaterialBatch 分组,并对QTY 值求和

代码如下:

var result = List1.Concat(
             List2.Select(list2Item => new List_Data
             {
                 Material = list2Item.Material,
                 Batch = list2Item.Batch,
                 QTY = list2Item.QTY * -1
             }))
             .GroupBy(item => new { item.Material, item.Batch })
             .Select(grouped => new List_Data
             {
                 Material = grouped.First().Material,
                 Batch = grouped.First().Batch,
                 QTY = grouped.Sum(item => item.QTY)
             })
             .ToList();

即使你有空的QTY,它仍然可以工作。例如,具有这些值:

List<List_Data> List1 = new List<List_Data>();
List1.Add(new List_Data { Material = "1", Batch = "B1", QTY = 5 });
List1.Add(new List_Data { Material = "1", Batch = "B2", QTY = 5 });
List1.Add(new List_Data { Material = "2", Batch = "B1", QTY = 15 });
List1.Add(new List_Data { Material = "3", Batch = "B1", QTY = null });
List1.Add(new List_Data { Material = "3", Batch = "B3", QTY = 4 });

List<List_Data> List2 = new List<List_Data>();
List2.Add(new List_Data { Material = "1", Batch = "B1", QTY = 2 });
List2.Add(new List_Data { Material = "3", Batch = "B1", QTY = 5 });
List2.Add(new List_Data { Material = "3", Batch = "B2", QTY = 15 });
List2.Add(new List_Data { Material = "3", Batch = "B3", QTY = null });

将导致:

Material: "1", Batch: "B1", QTY: 3
Material: "1", Batch: "B2", QTY: 5
Material: "2", Batch: "B1", QTY: 15
Material: "3", Batch: "B1", QTY: -5
Material: "3", Batch: "B3", QTY: 4
Material: "3", Batch: "B2", QTY: -15

【讨论】:

  • 是的。谢谢
  • @FrankFajardo 非常好的解决方案(+1)来自我。
  • 谢谢@Christos。我很感激。 :)
【解决方案2】:

如果我们假设在第二个列表中最多(如果有的话)一个元素具有相同的 MaterialBacth 值,那么一个天真的解决方案可能是以下:

// Initially project each element in the list to an element that 
// has also the info in which list this item is contained.
var list1 = List1.Select(x => new {Data = x, List = 1});
var list2 = List2.Select(x => new {Data = x, List = 2});

var result = list1.Concat(list2)
            .GroupBy(x => new {x.Data.Batch, x.Data.Material})
            .Select(gr =>
            {
                var itemsInGroup = gr.Count();
                if (itemsInGroup == 1)
                {
                    var onlyItemInGroup = gr.First();

                    if (onlyItemInGroup.List == 1)
                    {
                        return onlyItemInGroup.Data;
                    }

                    // Item came from the second list. So multiply it's quantity by -1.
                    onlyItemInGroup.Data.QTY *= -1;

                    return onlyItemInGroup.Data;
                }

                // Since for each item in list 1 there is at most one item in the list2
                // and vice versa itemsInGroup now is 2 and it is safe to use First as below
                // to grab the items.

                var itemFromFirstList = gr.First(x => x.List == 1);
                var itemFromSecondList = gr.First(x => x.List == 2);

                return new List_Data
                {
                    Material = gr.Key.Material,
                    Batch = gr.Key.Batch,
                    QTY = itemFromFirstList.Data.QTY - itemFromSecondList.Data.QTY
                };
            }).ToList();

在我们连接两个列表并根据键 MaterialBatch 对结果列表中的项目进行分组之后,基本上所有工作都在 Select 内完成。我们基于最初假设的选项如下:

  • 该组仅包含一个项目,该项目来自第一个列表。在这种情况下,我们只返回此项包含的数据。
  • 该组仅包含一个项目,该项目来自第二个列表。在这种情况下,我们必须将值 QTY 乘以 -1。请记住,您要使用的类型是list1.QTY - list2.QTY,并且在第一个列表list1 中没有任何关联元素。所以你想得到-list2.QTY,就像你声明的那样。
  • 该组包含两个项目,因为我们假设一个列表中最多(如果有的话)一个关联元素用于另一个列表中的另一个元素。在这种情况下,我们只需从list1.QTY 中减去list2.QTY 即可得到新的数量。

【讨论】:

  • 嗨,感谢您回答问题,但我在 ' item.Data.QTY *= -1; 中遇到错误' , 属性或索引器 'AnonymousType#1.QTY' 不能分配给 -- 它是只读的。
  • @DinukshiJayarathne 欢迎您。嗯...我执行了代码,但没有发现这个问题。顺便说一句,在List2 初始化之后,您必须使用List2.Add 而不是List1.Add。请更正这一点并让我知道。谢谢
【解决方案3】:

这里有另一个解决方案

var result = List1
    .Select(e => new        
    {
        key = new
        {
            e.Material, 
            e.Batch
        }, 
        QTY = e.QTY
    })
    .Concat(List2
        .Select(e => new
        {
            key = new
            {
                e.Material, 
                e.Batch
            }, 
            QTY = -e.QTY
        }))
    .GroupBy( e => e.key, e => e.QTY )
    .Select(g => new Report_Class
    {
        Material = g.Key.Material, 
        Batch = g.Key.Batch, 
        Difference = g.Sum()
    })
    .ToList();

.net fiddle sample

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-01-14
    • 1970-01-01
    • 2021-04-02
    • 1970-01-01
    • 1970-01-01
    • 2015-08-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多