如何调用Dictionary .TryGetValue()其中K:Predicate ,V:enum
我有Dictionary<Predicate, SomeEnum>
:
var dic = new Dictionary<Predicate, SomeEnum> { { (d) => d d > 90, SomeEnum.Bar } };
我想像这样打电话给TryGetValue(K, out V)
:
dic.TryGetValue(99)
并收到
SomeStruct.Bar
但TryGetValue()
第一个参数是Predicate
,而不仅仅是T
我怎么能做我想做的事?
我发现只有一个肮脏的解决方法:
var kpv = dic.FirstOrDefault(p => p.Key(99)); if (kpv.Key != null) var result = kpv.Value;
还有其他方法吗?
或者如何正确实现我的想法? – 声明一个键不是一个常量,而是一个段。
这里有一些问题:
Predicate
不适合用作TKey
。 字典的关键是识别一个值,而不是计算一个值。
使用lambdas也没有任何意义。 因为它们是匿名的,所以你不会得到任何等价,也不会使用字典。
有关说明,请参阅此代码示例:
Predicate fn_1 = d => d == 34.0d; Predicate fn_2 = d => d == 34.0d; // Note: There are not equal if (fn_1 == fn_2) Console.WriteLine("These are Equal?");
如果有的话,您可以使用委托列表并执行每个委托以查找匹配的委托,但此时您必须预期多个结果。 如果您只想获得单个结果,则必须考虑谓词在列表中的存储顺序 。
不要滥用KeyValuePair
作为没有Tuple
的黑客攻击。 创建一个既包含Predicate又包含SomeStruct的类相当容易。 看:
public class MySegment { public Predicate Predicate {get;set;} public SomeStruct Result {get;set;} }
要查看一系列谓词,找到匹配的谓词,如下所示:
... List list = new List (); ... list.Add(new MySegment { Predicate = d => d < 10, Result = SomeStruct.Foo }); list.Add(new MySegment { Predicate = d => d > 90, Result = SomeStruct.Bar }); ... public IEnumerable GetResults(double input) { foreach (var item in list) if (item.Predicate(input)) yield return item.Result; }
如果您的谓词列表不是太长,您只需将它们添加到List
,然后执行LINQ查询:
var lt10 = new KeyValuePair, SomeStruct>(d => d < 10, SomeStruct.Foo); var gt90 = new KeyValuePair, SomeStruct>(d => d > 90, SomeStruct.Bar); var predicates = new List, SomeStruct>>() { lt10, gt90 }; var result = predicates.FirstOrDefault(p => p.Key(99));
你最好使用SomeStruct?
而且,从那时起, FirstOrDefault
将提供一个明确的结果,如果它不匹配任何一个,而不是SomeStruct
。
如果列表很长,则需要考虑某种允许查询范围的数据结构,如间隔树 。
这不能使用Dictionary来完成,因为它依赖于哈希值来快速确定在哪里查找特定键。
正如您所发现的,您可以直接调用谓词,但这需要调用O(n)函数,这不比使用List,甚至是大的if / then / else语句更好。
如果您的潜在谓词集合太长而无法选择,那么您需要创建自己的数据结构以满足您的目的。 如果您只打算根据整数范围定义值,这应该不难,但如果您的谓词变得更复杂,它可能会失控。
另一方面,F#语言使用Match Expressions内置支持这种定义。 我不知道如何编译分支,但我认为它相当聪明。
编辑
以下是在F#中使用匹配表达式的示例:
// Define the "choose" function let choose value = match value with | v when v < 10 -> 1 | v when v > 90 -> 2 | _ -> 0 // Test the "choose" function let choice1 = choose 5 let choice2 = choose 15 let choice3 = choose 95
上面的代码产生以下值:
choice1 = 1 choice2 = 0 choice3 = 2
我之前从未真正使用过F#,所以你必须四处寻找如何在C#程序中使用F#中的函数。
您必须遍历您的条件并针对输入运行每个谓词以查看它是否匹配。 我认为没有理由在这里使用词典。