在 C# .NET 2.0 中,反向执行 foreach 的简单方法是什么?
-
01-07-2019 - |
题
假设我有一个 Dictionary 对象:
Dictionary myDictionary<int, SomeObject> = new Dictionary<string, SomeObject>();
现在我想以相反的顺序迭代字典。我无法使用简单的 for 循环,因为我不知道字典的键。A foreach 简单:
foreach (SomeObject object in myDictionary.Values)
{
// Do stuff to object
}
但我怎样才能反向执行此操作呢?
解决方案
我会使用 SortedList 而不是字典。您仍然可以通过 Key 访问它,但也可以通过索引访问它。
SortedList sCol = new SortedList();
sCol.Add("bee", "Some extended string matching bee");
sCol.Add("ay", "value matching ay");
sCol.Add("cee", "Just a standard cee");
// Go through it backwards.
for (int i = sCol.Count - 1; i >=0 ; i--)
Console.WriteLine("sCol[" + i.ToString() + "] = " + sCol.GetByIndex(i));
// Reference By Key
foreach (string i in sCol.Keys)
Console.WriteLine("sCol[" + i + "] = " + sCol[i]);
// Enumerate all values
foreach (string i in sCol.Values)
Console.WriteLine(i);
值得注意的是,排序列表存储仅按键排序的键/值对。
其他提示
字典或任何其他形式的哈希表没有顺序。所以你想做的事情是毫无意义的:)
如果您有 .NET 3.5,则可以在 IEnumerables 上使用 .Reverse() 扩展方法。例如:
foeach (SomeObject o in myDictionary.Values.Reverse())
{
// Do stuff to object
}
实际上,在 C# 2.0 中,您可以创建自己的迭代器来反向遍历容器。然后,您可以在 foreach 语句中使用该迭代器。但是你的迭代器首先必须有一种导航容器的方法。如果它是一个简单的数组,它可以像这样向后移动:
static IEnumerable<T> CreateReverseIterator<T>(IList<T> list)
{
int count = list.Count;
for (int i = count - 1; i >= 0; --i)
{
yield return list[i];
}
}
但当然,您不能使用 Dictionary 来做到这一点,因为它没有实现 IList 或提供索引器。说字典没有顺序是不正确的:当然是有秩序的。如果您知道它是什么,那么该命令甚至会很有用。
对于您的问题的解决方案:我想说将元素复制到数组中,然后使用上面的方法反向遍历它。像这样:
static void Main(string[] args)
{
Dictionary<int, string> dict = new Dictionary<int, string>();
dict[1] = "value1";
dict[2] = "value2";
dict[3] = "value3";
foreach (KeyValuePair<int, string> item in dict)
{
Console.WriteLine("Key : {0}, Value: {1}", new object[] { item.Key, item.Value });
}
string[] values = new string[dict.Values.Count];
dict.Values.CopyTo(values, 0);
foreach (string value in CreateReverseIterator(values))
{
Console.WriteLine("Value: {0}", value);
}
}
将值复制到数组似乎是一个坏主意,但根据值的类型,它实际上并没有那么糟糕。您可能只是复制参考资料!
我同意@leppie,但认为你应该得到这个问题的总体答案。可能您的本意是一般性问题,但无意中选择了错误的数据结构。字典中值的顺序应被视为特定于实现的;根据文档,它总是与键相同的顺序,但这个顺序也未指定。
无论如何,没有一个简单的方法来制作 foreach
反向工作。使用类的枚举器是一种语法糖,并且枚举器只能朝一个方向移动。从技术上讲,答案可能是“反转集合,然后枚举”,但我认为在这种情况下,您只需使用“向后”for 循环:
for (int i = myCollection.Length - 1; i >= 0; i--)
{
// do something
}
如果您没有 .NET 3.5,因此没有 Reverse 扩展方法,您可以实现自己的方法。我猜它可能会生成一个中间列表(必要时)并反向迭代它,如下所示:
public static IEnumerable<T> Reverse<T>(IEnumerable<T> items)
{
IList<T> list = items as IList<T>;
if (list == null) list = new List<T>(items);
for (int i = list.Count - 1; i >= 0; i-- )
{
yield return list[i];
}
}
那将是一个 Dictionary<int, SomeObject> myDictionary
, ,你可以这样做:
foreach(SomeObject _object in myDictionary.Values.Reverse())
{
}
我能想到的唯一方法 .NET 2.0 是首先将所有值复制到列表中,反转列表,然后在该列表上运行 foreach:
Dictionary<int, object> d;
List<object> tmplist;
foreach (object o in d.Values) tmplist.Add(s);
tmplist.Reverse();
foreach (object o in tmplist) {
//Do stuff
}
如果顺序最重要,您可以创建一个堆栈并创建一个简单的结构来存储 int、对象对。
一个标准 for
循环会是最好的。您不必担心反转集合的处理开销。
字面答案:
Dictionary<int, SomeObject> myDictionary = new Dictionary<int, SomeObject>();
foreach (var pair in myDictionary.OrderByDescending(i => i.Key))
{
//Observe pair.Key
//Do stuff to pair.Value
}
foreach (Sample in Samples)
try the following:
Int32 nEndingSample = Samples.Count - 1;
for (i = nEndingSample; i >= 0; i--)
{
x = Samples[i].x;
y = Samples[i].y;
}