繁体   English   中英

LINQ的两个列表之间的区别

[英]Difference between two lists with linq

我有两个带有两个字段的列表。 我不知道哪一个更大。

我想实现这一目标:

        newList              oldList
Fruit       Qty     Diff    Fruit       Qty
--------------------------------------------
apple       3       +1      apple       2
                    -2      pear        2
peach       4       +3      peach       1
melon       5        0      melon       5
coconut     2       +2      
mango       4        0      mango       4
banana      2       -1      banana      3
lychi       1       +1      
                    -3      pineapple   3

左边的一个您可以在oldList的右侧看到newList。 如果将oldList与newList进行比较,我想查看每个可能的行以及两个列表之间的数量差异。

我写了这个,这会给我两个列表中未包含的水果(xor)

var difference = newList.Select(x => x.Fruit)
                        .Except(oldList.Select(x => x.Fruit))
                        .ToList()
                        .Union(oldList.Select(x => x.Fruit)
                        .Except(newList.Select(x => x.Fruit))
                        .ToList());

但是我也不知道如何将其与Qty相结合。

我看不到使用LINQ的方法性能良好且可读性强的方法。 我希望混合使用LINQ和循环:

var oldGrouped = oldList.ToDictionary(x => x.Fruit, x => x.Qty);
var newGrouped = newList.ToDictionary(x => x.Fruit, x => x.Qty);

var result = new List<FruitSummary>();

foreach(var oldItem in oldGrouped)
{
    var summary = new FruitSummary { OldFruit = oldItem.Key, OldQty = oldItem.Value };
    if(newGrouped.TryGetValue(oldItem.Key, out int newQuantity) && newQuantity != 0)
    {
        summary.NewFruit = oldItem.Key;
        summary.NewQty = newQuantity;
    }
    summary.Diff = oldItem.Value - newQuantity;
    newGrouped.Remove(oldItem.Key);
    result.Add(summary);
}

foreach(var newItem in newGrouped)
{
    result.Add(new FruitSummary { Diff = -newItem.Value,
                                  NewFruit = newItem.Key,
                                  NewQty = newItem.Value });
}

FruitSummary看起来像这样:

public class FruitSummary
{
    public string OldFruit { get; set; }
    public string NewFruit { get; set; }
    public int OldQty { get; set; }
    public int NewQty { get; set; }
    public int Diff { get; set; }
}

我假设您有一个Fruit类,如下所示:

public class Fruit
{
    public string Name {get; set;}
    public int Quantity {get; set;}
}

而且您有一个这样的旧列表和新列表

List<Fruit> oldList = ...
List<Fruit> newList = ...

然后,这个LINQ monstrum就可以了,尽管它可能不是最高效的解决方案(但是有多少种水果?):

var result = 
    oldList.Join(newList, 
        oldFruit => oldFruit.Name,
        newFruit => newFruit.Name,
        (oldFruit, newFruit) => new {
            Name = oldFruit.Name,
            Diff = oldFruit.Quantity - newFruit.Quantity}).
    Concat(oldList.
        Where(oldFruit => newList.All(newFruit => newFruit.Name != oldFruit.Name)).
        Select(oldFruit => new {
            Name = oldFruit.Name,
            Diff = -oldFruit.Quantity})).
    Concat(newList.Where(newFruit => oldList.All(oldFruit => oldFruit.Name != newFruit.Name)).
        Select(newFruit => new {
            Name = newFruit.Name,
            Diff = newFruit.Quantity}));

您可以输出如下结果:

Console.WriteLine(string.Join(Environment.NewLine, result.Select(r => $"{r.Name} {r.Diff}")));

请注意,我之所以提出这个建议是因为我喜欢linq“一个内衬”,但使用foreach似乎比此查询更具可读性,甚至可能更快。

像这样吗

var difference = newList
    .Concat(oldList.Select(x => new { x.Fruit, Qty = -x.Qty }))
    .GroupBy(x => x.Fruit)
    .Select(g => new {Fruit = g.Key, Qty = g.Sum(x => x.Qty) });

当我运行foreach(var d in difference) Console.WriteLine(d); ,我得到:

{ Fruit = apple, Qty = 1 }
{ Fruit = peach, Qty = 3 }
{ Fruit = melon, Qty = 0 }
{ Fruit = coconut, Qty = 2 }
{ Fruit = mango, Qty = 0 }
{ Fruit = banana, Qty = -1 }
{ Fruit = lychi, Qty = 1 }
{ Fruit = pear, Qty = -2 }
{ Fruit = pineapple, Qty = -3 }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM