在C#.NET 2.0中,逆向进行foreach的简单方法是什么?

时间:2020-03-05 18:58:47  来源:igfitidea点击:

可以说我有一个Dictionary对象:

Dictionary myDictionary<int, SomeObject> = new Dictionary<string, SomeObject>();

现在,我想以相反的顺序遍历字典。我不能使用简单的for循环,因为我不知道字典的键。 foreach很简单:

foreach (SomeObject object in myDictionary.Values)
{
    // Do stuff to object
}

但是,我该如何反向执行呢?

解决方案

回答

字典或者任何其他形式的哈希表没有顺序。所以你想做的是没有意义的:)

回答

那将是Dictionary &lt;int,SomeObject> myDictionary,我们可以通过以下方式实现:

foreach(SomeObject _object in myDictionary.Values.Reverse())
{
}

回答

如果排序最重要,则可以堆栈并创建一个简单的结构来存储int,Object对。

回答

如果我们具有.NET 3.5,则可以在IEnumerables上使用.Reverse()扩展方法。例如:

foeach (SomeObject o in myDictionary.Values.Reverse())
{
     // Do stuff to object
}

回答

我可以在.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
}

回答

我同意@leppie,但认为我们总体上应该得到该问题的答案。可能是意思是笼统地问了这个问题,但不小心选择了一个错误的数据结构。字典中值的顺序应被视为特定于实现的;根据文档,它始终与键顺序相同,但是此顺序也未指定。

无论如何,没有一种简单的方法可以使" foreach"反向工作。使用该类的枚举器是语法糖,并且枚举器只能沿一个方向传播。从技术上讲,答案可能是"反转集合,然后枚举",但是我认为在这种情况下,我们只需要对循环使用"向后"即可:

for (int i = myCollection.Length - 1; i >= 0; i--)
{
    // do something
}

回答

如果我们需要字典类型集合,但需要维护插入顺序,则可以查看KeyedCollection
这里

它是字典和列表之间的合并。这样,我们可以通过键或者插入索引访问集合中的元素。

唯一的难题是,存储在集合中的元素是否必须具有int键。如果可以将其更改为字符串或者其他类型(Guid Mabye)。由于collection1将搜索键1而不是索引1.

回答

标准的" for"循环将是最好的。我们不必担心反转集合的处理开销。

回答

我会使用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);

值得注意的是,已排序列表仅存储按键排序的键/值对。

回答

实际上,在C2.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);
    }

}

将值复制到数组似乎不是一个好主意,但是根据值的类型,它并没有那么糟糕。我们可能只是在复制参考!

回答

我们可以使用LinqBridge在.NET 2.0中使用LINQtoObjects Enumerable.Reverse()函数。

回答

字面答案:

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
}

回答

如果我们没有.NET 3.5,因此没有反向扩展方法,则可以实现自己的方法。我猜想它可能会生成一个中间列表(必要时)并以相反的方式对其进行迭代,如下所示:

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];
    }
}