В С#.NET 2.0, какой простой способ сделать foreach в обратном порядке?
Допустим, у меня есть объект Dictionary:
Dictionary myDictionary<int, SomeObject> = new Dictionary<string, SomeObject>();
Теперь я хочу перебирать словарь в обратном порядке. Я не могу использовать простой цикл, потому что я не знаю ключей словаря. Простой легко:
foreach (SomeObject object in myDictionary.Values)
{
// Do stuff to object
}
Но как я могу выполнить это в обратном порядке?
Ответы
Ответ 1
Я бы использовал SortedList вместо словаря. Вы все равно можете получить к нему доступ с помощью ключа, но вы также можете получить к нему доступ по индексу.
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);
Стоит отметить, что отсортированный список сохраняет пары ключ/значение, отсортированные только по ключу.
Ответ 2
Словарь или любая другая форма хэш-таблицы не имеет порядка. Итак, что вы пытаетесь сделать, бессмысленно:)
Ответ 3
Если у вас есть .NET 3.5, вы можете использовать метод расширения .Reverse() для IEnumerables. Например:
foeach (SomeObject o in myDictionary.Values.Reverse())
{
// Do stuff to object
}
Ответ 4
Собственно, в С# 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];
}
}
Но, конечно, вы не можете сделать это с помощью Словаря, поскольку он не реализует 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);
}
}
Копирование ваших значений в массив может показаться плохой идеей, но в зависимости от типа значения это не так уж плохо. Вы можете просто копировать ссылки!
Ответ 5
Я согласен с @leppie, но думаю, что вы заслуживаете ответа на вопрос в целом. Возможно, вы имели в виду, что вопрос был вообще, но случайно выбрал плохую структуру данных. Порядок значений в словаре следует рассматривать как специфичный для реализации; согласно документации, это всегда тот же порядок, что и ключи, но этот порядок также не указан.
Во всяком случае, нет простого способа сделать foreach
работать в обратном порядке. Это синтаксический сахар для использования перечислителя класса, а счетчики могут перемещаться только в одном направлении. Технически ответ может быть "отменить сбор, а затем перечислить", но я думаю, что это случай, когда вам просто нужно использовать цикл "назад" для цикла:
for (int i = myCollection.Length - 1; i >= 0; i--)
{
// do something
}
Ответ 6
Если у вас нет .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];
}
}
Ответ 7
Это будет Dictionary<int, SomeObject> myDictionary
, и вы сделаете это:
foreach(SomeObject _object in myDictionary.Values.Reverse())
{
}
Ответ 8
Единственный способ, с помощью которого я могу найти в .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
}
Ответ 9
Если упорядочение является самым важным, вы можете создать Stack и создать простую структуру для хранения пары int, Object.
Ответ 10
Если вам нужна коллекция типов словарей, но вам нужно поддерживать порядок вставки, вы можете посмотреть в KeyedCollection
здесь
Это слияние словаря и списка. Таким образом, вы можете получить доступ к элементам в коллекции через ключ или индекс вставки.
Единственная проблема заключается в том, что ваш элемент, хранящийся в коллекции, должен иметь ключ int. Если вы можете изменить это на строку или другой тип (Guid Mabye). Поскольку коллекция 1 будет искать ключ из 1, а не индекс 1.
Ответ 11
Лучше всего будет стандартный цикл for
. Вам не нужно беспокоиться о накладных расходах на обратную обработку коллекции.
Ответ 12
Вы можете использовать LINQ to Objects Enumerable.Reverse() в .NET 2.0 с помощью LinqBridge.
Ответ 13
Буквальный ответ:
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
}
Ответ 14
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;
}