合并两个列表并从列表A中减去列表B的值

时间:2016-06-16 12:27:43

标签: c# .net performance entity-framework linq

我有以下列表,我想从列表Count

中减去列表B的属性A

以下是样本列表。请注意,我实际上使用的是Linq-To-Entities:

列出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}        
  };

我想通过使用相应A

列表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方法???

4 个答案:

答案 0 :(得分:5)

IMO这是left outer join的完美候选人:

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 :(得分:4)

您可以使用linq

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

主要部分是这一行

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

usedLeaves.FirstOrDefault(u => u.Id == x.Id)获取具有相同ID的Leave。如果它不存在则为null,因此整个usedLeaves.FirstOrDefault(u => u.Id == x.Id)?.Countnull,这会导致减去零,这不会影响计数。

答案 2 :(得分:2)

出于性能原因,我会将usedLeaves变成字典:

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

当然,如果第一个列表的Id未包含在第二个列表中,您可能需要添加一些错误处理:

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

对于较大的列表,建议将第二个转换为字典,因为IdFirstOrDefault()方式访问对象要比使用usedLeaves.AsEnumerable().ToDictionary()每次单独查看它们要快得多。

更新:没有考虑到我们在谈论EF。所以我不确定哪种方式更好。如果您想立即加载所有这些叶子并将它们保留在客户端,则必须致电FirstOrDefault() 正如我所说,我没有足够的经验来决定这是否比使用连续的.rocket-move-one { animation-timing-function: linear; } 电话寻找每一个更好。

答案 3 :(得分:1)

这是一个班轮:

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

正如Ivan Stoev所说,这是一个简单的LEFT JOIN。可以执行此操作的扩展方法是GroupJoin()