[英]Difference between two lists with linq
I have two lists with two fields. 我有两个带有两个字段的列表。 I don't know before hand which one is larger. 我不知道哪一个更大。
I want to achieve this: 我想实现这一目标:
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
One the left you can see newList on the right the oldList. 左边的一个您可以在oldList的右侧看到newList。 If I compare oldList against newList I want to see every possible row and difference in Quantity between the two lists. 如果将oldList与newList进行比较,我想查看每个可能的行以及两个列表之间的数量差异。
I wrote this, which would give me Fruit that's not contained in both lists (xor) 我写了这个,这会给我两个列表中未包含的水果(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());
But I'm lost on how to combine it with Qty as well. 但是我也不知道如何将其与Qty相结合。
I don't see a way with LINQ that performs well and is also readable. 我看不到使用LINQ的方法性能良好且可读性强的方法。 I would prefer a mix of LINQ and loops: 我希望混合使用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 });
}
The class FruitSummary
looks like this: 类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; }
}
I assume you have a Fruit
class like this: 我假设您有一个Fruit
类,如下所示:
public class Fruit
{
public string Name {get; set;}
public int Quantity {get; set;}
}
and you have an old and a new list like these 而且您有一个这样的旧列表和新列表
List<Fruit> oldList = ...
List<Fruit> newList = ...
Then this LINQ monstrum does the job, though it may not be the most performant solution (but how many kinds of fruit are there?): 然后,这个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}));
You can output the results like this: 您可以输出如下结果:
Console.WriteLine(string.Join(Environment.NewLine, result.Select(r => $"{r.Name} {r.Diff}")));
Note that I come up with this because I like linq "one liners", but using a foreach
seems more readable and probably even faster than this query. 请注意,我之所以提出这个建议是因为我喜欢linq“一个内衬”,但使用foreach
似乎比此查询更具可读性,甚至可能更快。
Something like this? 像这样吗
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) });
When I run foreach(var d in difference) Console.WriteLine(d);
当我运行foreach(var d in difference) Console.WriteLine(d);
, I get: ,我得到:
{ 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.