在日期范围内匹配的字典键
我想将数据存储在通用字典中,并使用在日期范围内匹配的键。
例如,我想出了以下想法
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 方法中的查找过程中使用它。
我想知道是否有其他人想出了一个优雅的解决方案来解决这个问题?
我应该提到,我将首先匹配密钥,然后可能会有特定密钥属性的日期范围。
I would like to store data in Generic Dictionary with keys that match over Date Ranges.
For instance, I came up with the following idea
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;
}
}
Then the I would use a Dictionary as so
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];
This was the best I could come up with, however it seems kludgy way to do this. I thought of adding a fourth property called selection date. And would set that to null in the entries in the dictionary but would use it during lookups in the Equals method.
I am wondering if anyone else has come up with an elegant solution to this problem?
I should mention that I will be matching on the key first and then there could be date ranges for the specific key property.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您对 Equals 的实现违反了覆盖 Equals 的准则。特别是您的实现不满足传递性规则:
违反这一准则是一个坏主意,可能会导致问题和混乱。我建议您不要这样做。
我会避免将间隔存储为字典中的键。如果您愿意,您可以将特定键的间隔列表作为值放入字典中,但它不应该是键的一部分。
当您搜索查找间隔时,您可以首先使用字典键来获取该键的间隔列表,然后迭代间隔以查找与您的参数重叠的间隔。如果特定键的间隔不重叠,那么您可以对它们进行排序并使用二分搜索来查找特定间隔。如果特定键的间隔可以重叠,您可以查看其他数据结构,例如 间隔树。
相关问题
Your implementation of Equals violates the guidelines for overriding Equals. In particular your implementation does not satisfy the transitivity rule:
Breaking this guideline is a bad idea and can lead to problems and confusion. I would recommend that you do not do this.
I would avoid storing intervals as keys in a dictionary altogether. You can put the list of intervals for a specific key as a value in the dictionary if you like, but it shouldn't be part of the key.
When you are searching to find an interval you can first use the dictionary key to get the list of intervals for that key and then iterate over the intervals to find one that overlaps with your parameter. If the intervals are not overlapping for a specific key then you can sort them and use a binary search to find a specific interval. If the intervals for a specific key can overlap you can look at other data structures such as an interval tree.
Related question
对于 getHashCode,返回
this.StartDate
和this.EndDate
以及this.Key
的哈希值。请参阅此页面了解简单的哈希想法。有更好的散列方法,但该页面应该可以帮助您入门。添加一个接受 int 键和单个 DateTime 的静态方法,因为看起来这就是您使用它的方式。 (如果需要,这可以在一个范围内采用两个日期时间)
return myDictionary[myDictionary.Keys.Find(x=> value < x.EndDate && value > x.StartDate) && x.Key = key];
对于两个日期:
return myDictionary[myDictionary.Keys.Find(x=> ((date1 < x.EndDate && date1 > x.StartDate)) || (date2 < x.EndDate && date2 > x.StartDate))) && x.Key = key];
如果您使用范围,则可以将其中任何一个查找全部,因为可能会发生冲突。
将等于条件更改为仅
返回 this.StartDate.Equals(o.StartDate) && this.EndDate.Equals(o.EndDate) && this.Key.Equals(o.Key);
使用上述静态方法,您不再需要重叠键的概念。
For getHashCode return a hash of
this.StartDate
andthis.EndDate
andthis.Key
. See this page for simple hashing ideas. There are better hashing methods out there but that page should get you started.Add a static method that takes in a int key and a single DateTime as it seems that is how you are using this. (this could take in two DateTimes for a range if you need it)
return myDictionary[myDictionary.Keys.Find(x=> value < x.EndDate && value > x.StartDate) && x.Key = key];
For two dates:
return myDictionary[myDictionary.Keys.Find(x=> ((date1 < x.EndDate && date1 > x.StartDate)) || (date2 < x.EndDate && date2 > x.StartDate))) && x.Key = key];
Either of these could be made a find all if you are using a range as there may be collisions.
Change your equals conditions to just
return this.StartDate.Equals(o.StartDate) && this.EndDate.Equals(o.EndDate) && this.Key.Equals(o.Key);
Using the above static method you no longer need the concept of overlapping keys.