不幸的是,除了将键复制到数组并在数组中向后索引之外,没有简单的方法可以向后迭代 Dictionary(或 SortedDictionary)。 (Linq 方法Enumerable.Reverse 实际上就是这样做的。)
如果您需要在这些年中向后和向前迭代,而不是 Dictionary<string, Dictionary<string, double>>,我建议使用 SortedList<TKey, TValue> 作为您的内部集合:
Dictionary<string, SortedList<string, double>>
甚至更好
Dictionary<string, SortedList<DateTime, double>>
这样做的好处是Keys 属性实现了Ilist<TKey>,因此您可以执行IndexOf,这将是log-n。如果您需要进行邻近查询(即查找最接近给定年份的年份),您可以推出自己的二分搜索:
public static int BinarySearch<T>(this IList<T> list, T value, IComparer<T> comparer)
{
// Adapted from http://referencesource.microsoft.com/#mscorlib/system/collections/generic/list.cs
if (list == null)
throw new ArgumentNullException("list");
comparer = comparer ?? Comparer<T>.Default;
int lo = 0;
int hi = list.Count - 1;
while (lo <= hi)
{
int i = lo + ((hi - lo) >> 1);
int order = comparer.Compare(list[i], value);
if (order == 0)
return i;
if (order < 0)
{
lo = i + 1;
}
else
{
hi = i - 1;
}
}
return ~lo;
}
SortedList 与Dictionary 相比的缺点是,如果您无序插入大量项目,则插入时间是 n 平方的。根据您的描述,我怀疑这对您来说不是问题。
更新
鉴于您每年的 SortedList 值,这里有一些您可以使用的扩展:
/// <summary>
/// Enumerate through all items in the list between first and last, inclusive. First and last need not be in the list.
/// </summary>
public static IEnumerable<KeyValuePair<TKey, TValue>> Between<TKey, TValue>(this SortedList<TKey, TValue> list, TKey first, TKey last)
{
if (list == null)
throw new ArgumentNullException();
var comparer = list.Comparer;
var index = list.Keys.BinarySearch(first, comparer);
if (index < 0) // There can be no duplicated keys in SortedList.
index = ~index;
for (int count = list.Count; index < count; index++)
{
var key = list.Keys[index];
if (comparer.Compare(key, last) > 0)
break;
yield return new KeyValuePair<TKey, TValue>(key, list.Values[index]);
}
}
public static SortedList<TKey, double> ComputeGrowth<TKey>(this SortedList<TKey, double> list)
{
var count = list.Count;
SortedList<TKey, double> newList = new SortedList<TKey, double>(count, list.Comparer);
for (int i = 0; i < count; i++)
{
if (i == 0)
newList.Add(list.Keys[i], 0.0); // Is this what you want?
else
newList.Add(list.Keys[i], (list.Values[i] - list.Values[i - 1]) / list.Values[i - 1]); // Any need to check for division by zero?
}
return newList;
}