Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/305.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 合并两个列表并从列表A中减去列表B的值_C#_.net_Performance_Entity Framework_Linq - Fatal编程技术网

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是否支持对话行动。。我使用它时使用了EFIf
Id
Leave
中的主键
FirstOrDefault
将命中索引,并且它没有任何性能问题。这也是我的观点。在我接受答案之前,我会尝试找出哪一个做得更好。FirstOrDefault就像是在一次迭代中查询列表???(我更正)@EduCielo是的,每次休假都会被调用,但正如我之前所说的,我对EF没有经验,所以我不知道这些调用在幕后是如何处理的。我认为这将在实体框架中使用。我怀疑linq2EF是否支持对话行动。。我使用它时使用了EFIf
Id
Leave
中的主键
FirstOrDefault
将命中索引,并且它没有任何性能问题。这也是我的观点。在我接受答案之前,我会尝试找出哪一个做得更好。FirstOrDefault就像是在一次迭代中查询列表???(我更正)@EduCielo是的,每次休假都会被要求,但正如我之前所说,我没有EF方面的经验,因此我不知道这些调用在幕后是如何处理的。问题和示例旨在显示值,但应用程序将来自EF的结果集。因此,这个问题对未来的读者来说将是非常误导的,因为您甚至已将术语列表添加到标题中。因此,这里可能的答案要么不会回答您的问题,要么不会回答使用Linq-To-Objects的未来读者的问题