我将DateTime的Date
部分作为查找值,并且喜欢在类型Dictionary<DateTime, double>
的字典中检索匹配值。请注意,DateTime键仅存储为日期部分。
我的问题是可能没有与我的查找值匹配的密钥。我当时喜欢做的是找到最近的 previous dateTime.Date键和匹配值。
现在,我知道词典没有按键排序。我可以使用SortedDictionary,但更喜欢使用Dictionary来解决特定原因,或者切换到List集合(可以预先排序)。我的问题是,在这种情况下你会建议做什么:在找到匹配的密钥之前保留Dictionary结构并递减查找值会更有效吗?或者使用列表集合并使用Linq会更好吗?每个词典包含大约5000个键/值对。此外,请注意我寻找一个高计算效率的解决方案,因为查找的频率非常高(可能数十万次(每次查找保证与以前的任何值不同)
答案 0 :(得分:5)
由于您需要快速,我认为最好的方法是使用BinarySearch
的结果。这需要List<T>
已排序。
int result = myList.BinarySearch(targetDate);
if (result >= 0)
return myList[result];
else
{
int nextLarger = ~result;
// return next smaller, or if that doesn't exist, the smallest one
return myList[Math.Max(0, nextLarger - 1)];
}
应该可以创建一个结合了Dictionary<TKey,TValue>
和排序List<TKey>
的类,它仍然像Dictionary<TKey,TValue>
一样序列化。序列化可能与在类中放置[JsonConverter(typeof(KeyValuePairConverter))]
一样简单(在Json.NET中)。
为了完整性,如果其他人在将来读到这篇文章,如果速度不是很重要,你可以用这样的东西更简单地做到:
var result = myDict.Keys.Where(x => x < targetDate).Max();
答案 1 :(得分:2)
我会使用自定义结构和集合来存储这些信息:
public struct DateValue
{
public DateValue(DateTime date, double val)
: this()
{
this.Date = date;
this.Value = val;
}
public DateTime Date { get; set; }
}
这是一个集合的可能实现,它包含所有DateValues
并封装逻辑以返回最近的。它使用List.BinarySearch
来查找它。如果找不到直接匹配,则使用BinarySearch
的逻辑来检测最近的:
指定数组中指定值的索引(如果值为) 找到。如果未找到值且值小于一个或多个 数组中的元素,负数是按位补码 第一个元素的索引大于value。如果有价值 找不到,值大于数组中的任何元素,a 负数,是(的指数)的按位补数 最后一个元素加上1)。
public class DateValueCollection : List<DateValue>, IComparer<DateValue>
{
public DateValueCollection() { }
public DateValueCollection(IEnumerable<DateValue> dateValues, bool isOrdered)
{
if (isOrdered)
base.AddRange(dateValues);
else
base.AddRange(dateValues.OrderBy(dv => dv.Date));
}
public DateValue GetNearest(DateTime date)
{
if (base.Count == 0)
return default(DateValue);
DateValue dv = new DateValue(date, 0);
int index = base.BinarySearch(dv, this);
if (index >= 0)
{
return base[index];
}
// If not found, List.BinarySearch returns the complement of the index
index = ~index;
DateValue[] all;
if(index >= base.Count - 1)
{
// proposed index is last, check previous and last
all = new[] { base[base.Count - 1], base[base.Count - 2] };
}
else if(index == 0)
{
// proposed index is first, check first and second
all = new[] { base[index], base[index + 1] };
}
else
{
// return nearest DateValue from previous and this
var thisDV = base[index];
var prevDV = base[index - 1];
all = new[]{ thisDV, prevDV };
}
return all.OrderBy(x => (x.Date - date).Duration()).First();
}
public int Compare(DateValue x, DateValue y)
{
return x.Date.CompareTo(y.Date);
}
}
快速测试:
var dateVals = new[] {
new DateValue(DateTime.Today.AddDays(10), 1), new DateValue(DateTime.Today, 3), new DateValue(DateTime.Today.AddDays(4), 7)
};
var dvCollection = new DateValueCollection(dateVals, false);
DateValue nearest = dvCollection.GetNearest(DateTime.Today.AddDays(1));
答案 2 :(得分:0)
为什么担心preomurley
做到这一点
然后,只有那么如果它慢,那么你有问题 使用分析器
进行测量然后理解从哪个点开始尝试其他方式并对其进行分析。
答案是:如果你以任何方式做到这一点,并且没有性能问题,你只是节省了时间,并设法做了一些有用的事情来增加你一天的价值。
过早优化不仅毫无意义,你通常会对你应该去的地方完全错误。