使用键值范围的字典对象

时间:2010-01-27 14:18:53

标签: c# .net dictionary lookup

我需要一种专门的字典。我的用例是这样的:用户想要指定值的范围(范围也可以是单个点)并为特定范围分配值。然后,我们想要使用单个值作为键来执行查找。如果此单个值出现在其中一个范围内,那么我们将返回与该范围相关联的值。

例如:

// represents the keyed value
struct Interval
{
    public int Min;
    public int Max;
}

// some code elsewhere in the program
var dictionary = new Dictionary<Interval, double>();
dictionary.Add(new Interval { Min = 0, Max = 10 }, 9.0);
var result = dictionary[1];
if (result == 9.0) JumpForJoy();

这显然只是一些代码来说明我正在寻找的东西。有谁知道实现这样的事情的算法?如果是这样,他们会指出我吗?

我已经尝试在Interval上实现自定义IEqualityComparer对象并重载Equals()和GetHashCode()但到目前为止无济于事。可能是我做错了。

8 个答案:

答案 0 :(得分:26)

字典不是您所描述的操作的适当数据结构。

如果要求间隔永远不会重叠,那么您只需构建一个有序间隔列表并对其进行二分搜索。

如果间隔可能重叠,那么您需要解决更难的问题。要有效地解决这个问题,你需要构建一个区间树:

http://en.wikipedia.org/wiki/Interval_tree

这是一个众所周知的数据结构。请参阅“算法简介”或任何其他关于数据结构的体面本科文本。

答案 1 :(得分:6)

仅当间隔不重叠时才会起作用。而你的主要问题似乎是从单个(键)值转换为间隔。

我会在SortedList周围写一个包装器。 SortedList.Keys.IndexOf()会找到一个索引,可用于验证间隔是否有效,然后使用它。

答案 2 :(得分:3)

这不是你想要的,但我认为它可能是你最接近的。

你当然可以比这更好(我早点喝酒了吗?)。但你必须承认它很简单。

var map = new Dictionary<Func<double, bool>, double>()
{
    { d => d >= 0.0 && d <= 10.0, 9.0 }
};

var key = map.Keys.Single(test => test(1.0))
var value = map[key];

答案 3 :(得分:1)

我已经通过确保集合是连续的来解决了类似的问题,其中间隔从不重叠并且它们之间从不存在间隙。每个间隔被定义为下边界,并且如果它等于或大于该边界并且小于下一个间隔的下边界,则任何值都在该间隔中。低于最低边界的任何东西都是特殊情况箱。

这有点简化了问题。然后,我们还通过实现二进制斩波来优化密钥搜索。不幸的是,我不能分享这些代码。

答案 4 :(得分:0)

我会做一个小的Interval类,就像那样:

public class Interval
{
    public int Start {get; set;}
    public int End {get; set;}
    public int Step {get; set;}
    public double Value {get; set;}

    public WriteToDictionary(Dictionary<int, double> dict)
    {
        for(int i = Start; i < End; i += Step)
        {
            dict.Add(i, Value);
        }
    }
}

所以你仍然可以在字典中进行正常查找。也许您还应该在调用Add()之前执行一些检查,或者如果字典中已有任何值,则执行某种回滚。

答案 5 :(得分:0)

您可以在Java flavored中找到区间树的Open Geospatial Library C#实现。它需要一些小的调整来解决你的问题,它也可以真正使用一些C#-ification。

它是开源的,但我不知道在什么许可下。

答案 6 :(得分:0)

我为字典 func 修改了一些构想,例如“ ChaosPandion”在上面的早些时候的帖子中给了我构想。 我仍然解决了编码问题,但是如果我尝试重构
我有一个令人惊讶的问题/错误/缺乏理解:

Dictionary<Func<string, double, bool>, double> map = new Dictionary<Func<string, double, bool>, double>()
{
        { (a, b) => a == "2018" && b == 4, 815.72},
        { (a, b) => a == "2018" && b == 6, 715.72}
};

这是什么,我用“ 2018”(年)和4(月)之类的搜索来调用地图,结果是双倍值815,72。 当我检查唯一的地图条目时,它们看起来像这样:

map working unique keys

所以这就是原始的行为,到目前为止还不错。 然后我尝试将其重构为:

Dictionary<Func<string, double, bool>, double> map = 
new Dictionary<Func<string, double, bool>, double>();

WS22(map, values2018, "2018");



private void WS22(Dictionary<Func<string, double, bool>, double> map, double[] valuesByYear, string strYear)
{
          int iMonth = 1;


             // step by step this works:
             map.Add((a, b) => (a == strYear) && (b == 1), dValue);
             map.Add((a, b) => (a == strYear) && (b == 2), dValue);



           // do it more elegant...
           foreach (double dValue in valuesByYear)
           {

             //this does not work: exception after second iteration of foreach run
              map.Add((a, b) => (a == strYear) && (b == iMonth), dValue );
              iMonth+=1; 
          }
}

this works: (i use b==1 and b==2)

this does not work (map not working exception on add item on second iteration)

所以我认为问题是,地图添加到地图字典时没有唯一键。问题是,我没有看到我的错误,为什么b == 1可以正常工作,而b == iMonth却不能正常工作。

谢谢你的帮助,打开我的眼睛:)

答案 7 :(得分:-2)

您可以查看codeplex上找到的有关可以执行所需内容的集合的powercollections。

希望这有帮助, 最好的祝福, 汤姆。