gpt4 book ai didi

linq - 在 LINQ 中使用 TryGetValue()?

转载 作者:行者123 更新时间:2023-12-04 23:32:16 24 4
gpt4 key购买 nike

此代码有效,但效率低下,因为它会重复查找 ignored字典。如何使用字典TryGetValue() LINQ 语句中的方法使其更高效?

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 参数。

最佳答案

(我的回答涉及使用 TrySomething( TInput input, out TOutput value ) 方法的一般情况(如 IDictionary.TryGetValue( TKey, out TValue )Int32.TryParse( String, out Int32 ) ,因此它不会直接用 OP 自己的示例代码回答 OP 的问题。我在这里发布这个答案是因为这个 QA 目前是谷歌的最高结果“linq trygetvalue”截至 2019 年 3 月)。

使用扩展方法语法时,至少有这两种方法。

1. 使用 C# 值元组、System.Tuple 或匿名类型:

TrySomething 调用中首先调用 Select 方法,并将结果存储在 C# 7.0 中的值元组中(或旧版本 C# 中的匿名类型,请注意,值元组应该是首选,因为它们的开销较低):

使用 C# 7.0 值元组(推荐):

// Task: Find and parse only the integers in this input:
IEnumerable<String> input = new[] { "a", "123", "b", "456", ... };

List<Int32> integersInInput = input
.Select( text => Int32.TryParse( text, out Int32 value ) ? ( ok: true, value ) : ( ok: false, default(Int32) ) )
.Where( t => t.ok )
.Select( t => t.value )
.ToList();

这实际上可以通过利用另一个巧妙的技巧来简化,其中 value 变量在整个 .Select lambda 的范围内,因此三元表达式变得不必要,如下所示:
// Task: Find and parse only the integers in this input:
IEnumerable<String> input = new[] { "a", "123", "b", "456", ... };

List<Int32> integersInInput = input
.Select( text => ( ok: Int32.TryParse( text, out Int32 value ), value ) ) // much simpler!
.Where( t => t.ok )
.Select( t => t.value )
.ToList();

使用 C# 3.0 匿名类型:
// Task: Find and parse only the integers in this input:
IEnumerable<String> input = new[] { "a", "123", "b", "456", ... };

List<Int32> integersInInput = input
.Select( text => Int32.TryParse( text, out Int32 value ) ? new { ok = true, value } : new { ok = false, default(Int32) } )
.Where( t => t.ok )
.Select( t => t.value )
.ToList();

使用 .NET Framework 4.0 Tuple<T1,T2> :
// Task: Find and parse only the integers in this input:
IEnumerable<String> input = new[] { "a", "123", "b", "456", ... };

List<Int32> integersInInput = input
.Select( text => Int32.TryParse( text, out Int32 value ) ? Tuple.Create( true, value ) : Tuple.Create( false, default(Int32) ) )
.Where( t => t.Item1 )
.Select( t => t.Item2 )
.ToList();

2.使用扩展方法

我编写了自己的扩展方法: SelectWhere,它将其简化为一次调用。它应该在运行时更快,尽管它不重要。

它通过为具有第二个 delegate 参数的方法声明自己的 out 类型来工作。 Linq 默认不支持这些,因为 System.Func 不接受 out 参数。但是,由于委托(delegate)在 C# 中的工作方式,您可以将 TryFunc 与任何与其匹配的方法一起使用,包括 Int32.TryParseDouble.TryParseDictionary.TryGetValue 等等...

要支持具有更多参数的其他 Try... 方法,只需定义一个新的委托(delegate)类型并为调用者提供一种指定更多值的方法。
public delegate Boolean TryFunc<T,TOut>( T input, out TOut value );

public static IEnumerable<TOut> SelectWhere<T,TOut>( this IEnumerable<T> source, TryFunc<T,TOut> tryFunc )
{
foreach( T item in source )
{
if( tryFunc( item, out TOut value ) )
{
yield return value;
}
}
}

用法:
// Task: Find and parse only the integers in this input:
IEnumerable<String> input = new[] { "a", "123", "b", "456", ... };

List<Int32> integersInInput = input
.SelectWhere( Int32.TryParse ) // The parse method is passed by-name instead of in a lambda
.ToList();

如果您仍想使用 lambda,另一种定义使用值元组作为返回类型(需要 C# 7.0 或更高版本):
public static IEnumerable<TOut> SelectWhere<T,TOut>( this IEnumerable<T> source, Func<T,(Boolean,TOut)> func )
{
foreach( T item in source )
{
(Boolean ok, TOut output) = func( item );

if( ok ) yield return output;
}
}

用法:
// Task: Find and parse only the integers in this input:
IEnumerable<String> input = new[] { "a", "123", "b", "456", ... };

List<Int32> integersInInput = input
.SelectWhere( text => ( Int32.TryParse( text, out Int32 value ), value ) )
.ToList();

这是因为 C# 7.0 允许在 out Type name 表达式中声明的变量用于其他元组值。

关于linq - 在 LINQ 中使用 TryGetValue()?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3280589/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com