在 LINQ 中使用 TryGetValue() 吗?
此代码可以工作,但效率低下,因为它会双重查找 ignored
字典。如何在 LINQ 语句中使用字典 TryGetValue()
方法来提高效率?
IDictionary<int, DateTime> records = ...
IDictionary<int, ISet<DateTime>> ignored = ...
var result = from r in records
where !ignored.ContainsKey(r.Key) ||
!ignored[r.Key].Contains(r.Value)
select r;
问题是我不确定如何在 LINQ 语句中声明用于 out 参数的变量。
This code works, but is inefficient because it double-lookups the ignored
dictionary. How can I use the dictionary TryGetValue()
method in the LINQ statement to make it more efficient?
IDictionary<int, DateTime> records = ...
IDictionary<int, ISet<DateTime>> ignored = ...
var result = from r in records
where !ignored.ContainsKey(r.Key) ||
!ignored[r.Key].Contains(r.Value)
select r;
The problem is I'm not sure how to declare a variable within the LINQ statement to use for the out parameter.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
(我的回答涉及使用
TrySomething( TInput input, out TOutput value )
方法的一般情况(例如IDictionary.TryGetValue( TKey, out TValue )
和Int32。 TryParse( String, out Int32 )
因此它不会直接用OP自己的exmaple代码回答OP的问题,我在这里发布这个答案是因为这个QA目前是“linq trygetvalue”的Google最高结果。 2019 年 3 月)。使用扩展方法语法时,至少有以下两种方法:
使用 C# 值元组、
System.Tuple
或匿名类型:调用
TrySomething<。首先在
Select
调用中使用 /code> 方法,并将结果存储在 C# 7.0 中的值元组中(或旧版本 C# 中的匿名类型,请注意,应首选值元组,因为它们的开销较低):使用 C# 7.0 值元组(推荐):
实际上可以通过利用另一个巧妙的技巧来简化,其中
value
变量在整个.Select 的范围内
lambda,因此三元表达式变得不必要,如下所示:使用 C# 3.0 匿名类型:
使用 .NET Framework 4.0
Tuple
:扩展方法
2. 使用我编写的 自己的扩展方法:
SelectWhere
将其减少为单个调用。它在运行时应该更快,尽管这并不重要。它的工作原理是为具有第二个
out
参数的方法声明自己的delegate
类型。 Linq 默认情况下不支持这些,因为System.Func
不接受out
参数。但是,由于委托在 C# 中的工作方式,您可以将TryFunc
与任何与其匹配的方法一起使用,包括Int32.TryParse
、Double .TryParse
、Dictionary.TryGetValue
等...要支持其他具有更多参数的
Try...
方法,只需定义一个新的委托类型并为调用者提供一种指定更多值的方法。用法:
如果您仍想使用 lambda,则可以使用替代定义使用值元组作为返回类型(需要 C# 7.0 或更高版本):
用法:
这有效,因为 C# 7.0 允许在
out 类型名称< 中声明变量/code> 用于其他元组值的表达式。
(My answer concerns the general case of using
TrySomething( TInput input, out TOutput value )
methods (likeIDictionary.TryGetValue( TKey, out TValue )
andInt32.TryParse( String, out Int32 )
and so it does not directly answer the OP's question with the OP's own exmaple code. I'm posting this answer here because this QA is currently the top Google result for "linq trygetvalue" as of March 2019).When using the extension method syntax there are at least these two approaches.
1. Using C# value-tuples,
System.Tuple
, or anonymous-types:Call the
TrySomething
method first in aSelect
call, and store the outcome in a value-tuple in C# 7.0 (or anonymous-type in older versions of C#, note that value-tuples should be preferred due to their lower overhead):Using C# 7.0 value-tuples (recommended):
This can actually be simplified by taking advantage of another neat trick where the
value
variable is in-scope for the entire.Select
lambda, so the ternary expression becomes unnecessary, like so:Using C# 3.0 anonymous types:
Using .NET Framework 4.0
Tuple<T1,T2>
:2. Use an extension method
I wrote my own extension method:
SelectWhere
which reduces this to a single call. It should be faster at runtime though it shouldn't matter.It works by declaring its own
delegate
type for methods that have a secondout
parameter. Linq doesn't support these by default becauseSystem.Func
does not acceptout
parameters. However due to how delegates work in C#, you can useTryFunc
with any method that matches it, includingInt32.TryParse
,Double.TryParse
,Dictionary.TryGetValue
, and so on...To support other
Try...
methods with more arguments, just define a new delegate type and provide a way for the caller to specify more values.Usage:
If you still want to use a lambda, an alternative definition uses a value-tuple as the return type (requires C# 7.0 or later):
Usage:
This works because C# 7.0 allows variables declared in an
out Type name
expression to be used in other tuple values.您需要在查询之前声明
out
变量:不过,如果稍后才评估查询,请注意副作用...
You need to declare the
out
variable before the query :Be careful of side effects if the query isn't evaluated until later, though...
使用外部变量,您无需担心它超出范围,因为 LINQ 表达式是一个可以使其保持活动状态的闭包。但是,为了避免任何冲突,您可以将变量和表达式放在一个函数中:
这样,只有查询才能访问
s
变量,而任何其他查询(从单独调用返回) GetRecordQuery
) 每个都有自己的变量实例。Using an external variable, you don't need to worry about it going out of scope because the LINQ expression is a closure that will keep it alive. However to avoid any conflicts, you could put the variable and expression in a function:
That way, only the query has access to the
s
variable, and any other queries (returned from separate calls toGetRecordQuery
) will each have their own instance of the variable.