2016-06-16 10 views
1

からリストBの値を引きサンプルリストです。私は実際にLINQのツーエンティティ使用してきたことに注意してください:は、2つのリストをマージして、私は次のリストを持っていると私はここで<code>A</code></p> <p>リストからリスト<code>B</code>のプロパティ<code>Count</code>を減算したいリストA

リストAを

List<Leave> defaultLeaves = new List<Leave>() 
{ 
    new Leave{ Id = 1 , Count = 7}, 
    new Leave{ Id = 2 , Count = 7}, 
    new Leave{ Id = 3 , Count = 7}, 
    new Leave{ Id = 4 , Count = 3} 
}; 

リストB

List<Leave> usedLeaves = new List<Leave>() 
{ 
    new Leave{ Id = 1 , Count = 1}, 
    new Leave{ Id = 2 , Count = 2}   
    }; 

私はあることを、リストの出力を持つようにしたいですこれは、リストからのカウントを、リストBのそれぞれのカウントを用いて減算することによって、Ids

List<Leave> availableLeaves = new List<Leave>() 
{ 
    new Leave{ Id = 1 , Count = 6}, 
    new Leave{ Id = 2 , Count = 5}, 
    new Leave{ Id = 3 , Count = 7}, 
    new Leave{ Id = 4 , Count = 3} 
}; 

これはlinqメソッドを使用して可能ですか?

+0

です。質問と例は値を示していますが、アプリケーションはEf –

+2

の結果セットからのものです。この質問は、将来の読者にとっては誤解を招くタイトルのリスト。ここで可能な答えはあなたの質問に答えないか、Linq-To-Objectsを使う将来の読者の質問に答えないでしょう。 –

+0

次にポイントに合わせて編集を提案できますか? –

答えて

4

あなたは主要部分は、このライン

Count = x.Count - usedLeaves.FirstOrDefault(u => u.Id == x.Id)?.Count ?? 0 

usedLeaves.FirstOrDefault(u => u.Id == x.Id)は、同じIDを持つLeaveを取得しているLINQ

var availableLeaves = defaultLeaves.Select(x => new Leave() 
{ 
    Id = x.Id, 
    Count = x.Count - usedLeaves.FirstOrDefault(u => u.Id == x.Id)?.Count ?? 0 
}).ToList(); 

を使用することができます。存在しない場合はnullなので、usedLeaves.FirstOrDefault(u => u.Id == x.Id)?.Countnullであり、これはカウントに影響を与えない0を引きます。私は辞書にusedLeavesを回すでしょうパフォーマンス上の理由から

+0

スマートなのいずれかが0 –

+3

を処理するために...今、それを読み取ることが難しくなって'?.'(これはC#6でのみ利用可能です)。 – juharr

+0

@juharr私の誤って...私は間違って3進数として識別しました.. –

2

var dic = usedLeaves.ToDictionary(l => l.Id, l => l.Count); 

それから私は、結果のリストを生成するためにこれを使用します。もちろん

availableLeaves = defaultLeaves.Select(l => 
        new Leave {Id = l.Id, Count = l.Count - dic[l.Id]}) 
        .ToList(); 

をあなたには、いくつかのエラー処理を追加したい場合があります第1リストのIdが第2リストに含まれていない場合:

availableLeaves = defaultLeaves.Select(l => 
        { 
        int count; 
        if (!dic.TryGetValue(l.Id, out count)) 
         count = 0;       
        return new Leave {Id = l.Id, Count = l.Count - count}); 
        }).ToList(); 

大きなリストの場合は、Idでオブジェクトにアクセスすると、1回の休暇ごとにFirstOrDefault()を使用して検索するよりも、この方法の方がはるかに高速です。

更新:EFについて話していることを考慮していませんでした。だから私はどちらが良い方法であるか分からない。一度にすべてのリーフをロードしてクライアント側に保管したい場合は、usedLeaves.AsEnumerable().ToDictionary()に電話する必要があります。
私が言ったように、私はこれが連続してFirstOrDefault()コールを使用するすべてのものを求めているよりも優れているかどうかを判断するのに十分な経験はありません。

+0

は、私はこのつもりがエンティティフレームワークで使用することを考える –

+0

...私はそこにあなたのポイントを参照してくださいました。私はlinq2EFが実際にToDictionary – dotctor

+0

をサポートしてい疑う..私は 'Id'は' FirstOrDefault'がインデックスにヒットするLeave' 'の主キーであり、そうでない場合は答え –

5

IMOこれはleft outer joinのための完璧な候補である:イワンStoevは、これは単純なLEFT JOINのある、示唆したように

var leaves = defaultLeaves.GroupJoin(usedLeaves, dl => dl.Id, ul => ul.Id, 
      (dl, ulList) => new Leave { Id = dl.Id, Count = dl.Count - (ulList.Any() ? ulList.FirstOrDefault().Count : 0) }); 

var availableLeaves = 
    (from d in defaultLeaves 
    join u in usedLeaves on d.Id equals u.Id into match 
    from u in match.DefaultIfEmpty() 
    select new Leave 
    { 
     Id = d.Id, 
     Count = d.Count - (u != null ? u.Count : 0) 
    }).ToList(); 
+1

OMG、そのことを考えていなかった... + 1 –

+1

や 'カウント= d.Count - ?U .Countを?? 0 'となる。 – juharr

+1

これは、Linq-To.ObjectsやLinq-To-Entitiesのような他のLinqプロバイダのための汎用的なソリューションです。 –

1

そして、ここでは1つのライナーです。それを可能にする拡張メソッドはGroupJoin()

関連する問題