【问题标题】:Dictionary Keys that match over a Date Range在日期范围内匹配的字典键
【发布时间】:2010-07-30 18:08:28
【问题描述】:

我想用在日期范围内匹配的键将数据存储在通用字典中。

例如,我想出了以下想法

public class MyKey : IEquatable<MyKey> 
{
  public int Key { get; set; }
  public DateTime StartDate { get; set; }
  public DateTime EndDate { get; set; }

  public override int GetHashCode() 
  { 
    returns Key;
  }

  // if there is overlap in date range consider them equal
  public bool Equals(MyKey other)
  {
    if (Key!=other.Key)
      return false;
    else if(other.StartDate >=StartDate && other.StartDate <=EndDate) 
      return true;
    else if(other.EndDate >=StartDate && other.EndDate <=EndDate) 
      return true;
    else if(StartDate >=other.StartDate && StartDate <=other.EndDate) 
      return true;
    else if(EndDate >=other.StartDate && EndDate <=other.EndDate) 
      return true;
    else
      return false;
  }
}

那么我会像这样使用字典

var dict = new Dictionary<MyKey,MyClass>();
Populate(dict);

// get an element where the current date is in the daterange of the key
// in the collection
var key = new MyKey();
key.Key=7;
key.StartDate=DateTime.Now;
key.EndDate=key.StartDate;

// retrieve the matching element for the date
var myclass = dict[key];

这是我能想到的最好的方法,但是这样做似乎很笨拙。我想添加第四个属性,称为选择日期。并且会在字典中的条目中将其设置为 null,但会在 Equals 方法中的查找期间使用它。

我想知道是否有其他人想出一个优雅的解决方案来解决这个问题?

我应该提到,我将首先匹配键,然后可能会有特定键属性的日期范围。

【问题讨论】:

标签: c# collections dictionary


【解决方案1】:

您的 Equals 实现违反了guidelines for overriding Equals。特别是您的实现不满足传递性规则:

  • 如果x.Equals(y) &amp;&amp; y.Equals(z)返回真,那么x.Equals(z)返回真。

违反此准则是个坏主意,可能会导致问题和混乱。我建议你不要这样做。

我会完全避免将间隔存储为字典中的键。如果愿意,您可以将特定键的间隔列表作为 放入字典中,但它不应该是键的一部分。

当您搜索区间时,您可以首先使用字典键获取该键的区间列表,然后遍历区间以找到与您的参数重叠的区间。如果特定键的间隔不重叠,那么您可以对它们进行排序并使用二进制搜索来查找特定间隔。如果特定键的间隔可以重叠,您可以查看其他数据结构,例如 interval tree

相关问题

【讨论】:

  • 我在等于比较中遗漏了一行。如果 Key 本身不匹配,则 equals 将返回 false。所以我不认为这违反了你提到的关于哈希码的规则。对此感到抱歉。
  • @Jeff:根据您对问题的更新,我对我的答案进行了相当多的更改。
  • 谢谢,马克。我认为间隔树是不合适的,因为主要查找是基于一个键的,并且在大多数情况下不会有其他间隔。传递性规则很有趣。如果 MyKey 仅设计为字典的键,我不确定违反此规则的含义是什么。此时看来,我将不得不切换到列表类型结构并仅搜索匹配项,或者将我存储在字典中的对象更改为不同范围内相同键的对象集合。
【解决方案2】:

对于 getHashCode,返回 this.StartDatethis.EndDatethis.Key 的哈希值。请参阅this page 了解简单的散列思想。有更好的散列方法,但该页面应该可以帮助您入门。

添加一个静态方法,该方法接受一个 int 键和一个 DateTime,因为这似乎就是您使用它的方式。 (如果需要,这可以在一个范围内占用两个 DateTimes) return myDictionary[myDictionary.Keys.Find(x=&gt; value &lt; x.EndDate &amp;&amp; value &gt; x.StartDate) &amp;&amp; x.Key = key];

对于两个日期: return myDictionary[myDictionary.Keys.Find(x=&gt; ((date1 &lt; x.EndDate &amp;&amp; date1 &gt; x.StartDate)) || (date2 &lt; x.EndDate &amp;&amp; date2 &gt; x.StartDate))) &amp;&amp; x.Key = key];

如果您使用范围,则其中任何一个都可以全部查找,因为可能会发生冲突。

将您的等于条件更改为

return this.StartDate.Equals(o.StartDate) &amp;&amp; this.EndDate.Equals(o.EndDate) &amp;&amp; this.Key.Equals(o.Key);

使用上述静态方法,您不再需要重叠键的概念。

【讨论】:

  • 我忽略了键也必须相等。将其添加到已编辑的问题中?
  • 杰克,这种静态查找方法似乎可行,但我们似乎并没有真正利用字典的散列特性,因为我们将遍历键以找到匹配项.不过,这似乎是最简单的实现方式。
  • 我接受了这个答案,因为它是我最终实现的。间隔列表似乎不起作用,因为在大多数情况下,关键是最重要的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-01-14
  • 2014-01-07
  • 2019-07-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多