1

我有Dictionary<Predicate<double>, SomeEnum>

var dic = new Dictionary<Predicate<double>, SomeEnum>
{
    { (d) => d < 10, SomeEnum.Foo },
    { (d) => d > 90, SomeEnum.Bar }
};

我想这样TryGetValue(K, out V)反对它:

dic.TryGetValue(99)

并收到

SomeStruct.Bar

但第一个参数TryGetValue()Predicate<T>,不只是T。我怎样才能做我想做的事?

我发现只有一个肮脏的解决方法:

var kpv = dic.FirstOrDefault(p => p.Key(99));
if (kpv.Key != null)
    var result = kpv.Value;

还有其他方法吗?

或者如何正确实施我的想法?- 声明一个键不是一个常量,而是一个段。

4

4 回答 4

3

这里有几件事是错误的:

Predicate<double>不适合用作TKey. 字典的键应该识别一个值,而不是计算一个值。

使用 lambdas 也没有任何意义。因为它们是匿名的,所以您不会得到任何等价物,也无法使用字典。

请参阅此代码示例以获取说明:

Predicate<double> fn_1 = d => d == 34.0d;
Predicate<double> fn_2 = d => d == 34.0d;

// Note: There are not equal
if (fn_1 == fn_2)
    Console.WriteLine("These are Equal?");

如果有的话,您可以使用委托列表并执行每个委托以找到匹配的委托,但此时您必须期待多个结果。如果您只想获得一个结果,那么您必须考虑谓词在列表中的存储顺序。

不要KeyValuePair因为没有Tuple<T1,T2>. 创建一个同时具有 Predicate 和 SomeStruct 的类是相当容易的。看:

public class MySegment
{   
     public Predicate<double> Predicate {get;set;}
     public SomeStruct Result {get;set;}
}

要遍历一系列谓词,并找到匹配的谓词,如下所示:

...
List<MySegment> list = new List<MySegment>();
...
list.Add(new MySegment { Predicate = d => d < 10, Result = SomeStruct.Foo });
list.Add(new MySegment { Predicate = d => d > 90, Result = SomeStruct.Bar });

...

public IEnumerable<SomeStruct> GetResults(double input)
{ 
    foreach (var item in list)
        if (item.Predicate(input))
             yield return item.Result;
}
于 2010-11-29T21:10:39.367 回答
2

如果您的谓词列表不太长,您可以将它们添加到 aList<KeyValuePair<Predicate<T>, V>>然后执行 LINQ 查询:

var lt10 = new KeyValuePair<Predicate<Double>, SomeStruct>(d => d < 10, SomeStruct.Foo);
var gt90 = new KeyValuePair<Predicate<Double>, SomeStruct>(d => d > 90, SomeStruct.Bar);
var predicates = new List<KeyValuePair<Predicate<Double>, SomeStruct>>() { lt10, gt90 };

var result = predicates.FirstOrDefault(p => p.Key(99));

此外,您最好使用SomeStruct?而不是SomeStruct,因为FirstOrDefault如果它不匹配任何内容,则会给出明确的结果。

如果您的列表很长,您将需要考虑某种允许在某个范围内查询的数据结构,例如区间树

于 2010-11-29T20:16:04.300 回答
2

这不能使用字典来完成,因为它依赖于哈希值来快速确定在哪里查找特定键。

正如您所发现的,您可以直接调用谓词,但这需要调用 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# 中的函数。

于 2010-11-29T20:25:37.187 回答
0

您必须遍历您的条件并针对输入运行每个 Predicate 以查看它是否匹配。我看不出有任何理由在这里使用字典。

于 2010-11-29T20:17:49.873 回答