2016-03-31 15 views
0

2つのフィールドを持つ2つのリストがあります。私は手前でどれが大きいかわからない。linqでの2つのリストの相違

は、私はこれを達成したい:

 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を比較すると、2つのリスト間の可能なすべての行と数量の差異を確認したいと考えています。

私は私に、両方のリストに含まれていない果実(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()); 

を与えることになる、これを書いたしかし、私は、同様に数量とそれを組み合わせる方法に迷ってしまいました。

+0

これは、ループ内で、通常の 'foreach'して、簡単なLINQを使用するもののようなもののように思えます。そして、これらは本当にリストですか?それとも実際に辞書ですか? – ryanyuyu

+0

あなたの 'フルーツ'はクラスですか?もしそうなら、あなたの質問にそれを加えてください。 – Cameron

+0

これらのリストは、データベースからのlinqクエリの結果で、果物と数量の2つの列のみを使用した結果です。だからフルーツは野原です。 – Zikato

答えて

3

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) 
{ 
    int newQuantity; 
    newGrouped.TryGetValue(oldItem.Key, out newQuantity) 
    var summary = new FruitSummary { OldFruit = oldItem.Key, OldQty = oldItem.Value }; 
    if(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 Fruit 
{ 
    public string Name {get; set;} 
    public int Quantity {get; set;} 
} 

とあなた:

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

私はあなたがこのようなFruitクラスを持っていると仮定しますこのような古いリストと新しいリストがある

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を好きなので、私はこれを考え出す注「1ライナー」を、しかしforeachを使用すると、より読みやすく、おそらくさらに速く、このクエリよりも思えます。

0

これは何か?私はforeach(var d in difference) Console.WriteLine(d);を実行すると

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

、私が手:

{ 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 } 
関連する問題