C# 合并两个列表并从列表A中减去列表B的值
我有以下列表,我想从列表C# 合并两个列表并从列表A中减去列表B的值,c#,.net,performance,entity-framework,linq,C#,.net,Performance,Entity Framework,Linq,我有以下列表,我想从列表A中减去列表B的属性Count 以下是示例列表。请注意,我实际上使用Linq转换实体: 列出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
A
中减去列表B
的属性Count
以下是示例列表。请注意,我实际上使用Linq转换实体:
列出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}
};
这是否可能使用linq方法???您可以使用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
usedleves.FirstOrDefault(u=>u.Id==x.Id)
获取具有相同Id的Leave
。如果它不存在,则为null
,因此整个usedleves.FirstOrDefault(u=>u.Id==x.Id)?。Count
为null
,这会导致减去零,而不会影响计数。您可以使用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
usedleves.FirstOrDefault(u=>u.Id==x.Id)
获取具有相同Id的离开。如果它不存在,则它是null
因此整个usedleves.FirstOrDefault(u=>u.Id==x.Id)?.Count
为null
,这会导致减去零,而不影响计数。出于性能原因,我会将usedleves
转换为字典:
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();
对于较大的列表,建议将第二个列表转换为字典,因为通过Id
访问对象,这种方式比每次离开都使用FirstOrDefault()
查找对象快得多
更新:没有考虑到我们正在谈论的EF。所以我不确定哪种方法更好。如果要同时加载所有这些叶子并将它们保留在客户端,则必须调用usedLeaves.AsEnumerable().ToDictionary()
。
正如我所说,我没有足够的经验来判断这是否比使用连续的FirstOrDefault()
调用来查找每一个调用更好。出于性能原因,我将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();
对于较大的列表,建议将第二个列表转换为字典,因为通过Id
访问对象,这种方式比每次离开都使用FirstOrDefault()
查找对象快得多
更新:没有考虑到我们正在谈论的EF。所以我不确定哪种方法更好。如果要同时加载所有这些叶子并将它们保留在客户端,则必须调用usedLeaves.AsEnumerable().ToDictionary()
。
正如我所说,我没有足够的经验来判断这是否比使用连续的FirstOrDefault()
调用来查找每一个函数更好。在我看来,这是一个完美的选择:
IMO这是一个完美的候选人:
这是一条单行线:
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所建议的,这是一个简单的左连接。可以做到这一点的扩展方法是GroupJoin()
,下面是一个单行程序:
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所建议的,这是一个简单的左连接。可以做到这一点的扩展方法是GroupJoin()
更光滑的方法,它使用三元组来处理0@EduCielo这不是三元运算符(实际上称为条件运算符?:
),而是空合并运算符?
和空条件运算符?。
(仅在C#6中可用).@juharr?
是空传播运算符;)@勒内·福格特并没有这样说。虽然我会这样称呼它。@juharr似乎有不同的名字,但你可能是对的,条件是官方版本。更圆滑的一个使用三元来处理0@EduCielo这不是三元运算符(实际上称为条件运算符?:
)这是空合并运算符?
和空条件运算符?。
(仅在C#6中可用)。@juharr?
是空传播运算符;)@勒内·福格特并没有这样说。虽然我会这样称呼它。@juharr似乎有不同的名字,但你可能是对的,条件是官方版本。我想这将在实体框架中使用。我怀疑linq2EF是否支持对话行动。。我使用它时使用了EFIfId
是Leave
中的主键FirstOrDefault
将命中索引,并且它没有任何性能问题。这也是我的观点。在我接受答案之前,我会尝试找出哪一个做得更好。FirstOrDefault就像是在一次迭代中查询列表???(我更正)@EduCielo是的,每次休假都会被调用,但正如我之前所说的,我对EF没有经验,所以我不知道这些调用在幕后是如何处理的。我认为这将在实体框架中使用。我怀疑linq2EF是否支持对话行动。。我使用它时使用了EFIfId
是Leave
中的主键FirstOrDefault
将命中索引,并且它没有任何性能问题。这也是我的观点。在我接受答案之前,我会尝试找出哪一个做得更好。FirstOrDefault就像是在一次迭代中查询列表???(我更正)@EduCielo是的,每次休假都会被要求,但正如我之前所说,我没有EF方面的经验,因此我不知道这些调用在幕后是如何处理的。问题和示例旨在显示值,但应用程序将来自EF的结果集。因此,这个问题对未来的读者来说将是非常误导的,因为您甚至已将术语列表添加到标题中。因此,这里可能的答案要么不会回答您的问题,要么不会回答使用Linq-To-Objects的未来读者的问题