11 ответов:
при работе со списком (прямая индексация), вы не можете сделать это так же эффективно, как с помощью
forпетли.Edit: что обычно означает, когда вы в состоянии использовать
forцикл, это, вероятно, правильный метод для этой задачи. Плюс, за столько, сколькоforeachреализуется в порядке, сама конструкция построена для выражения циклов, которые не зависят от индексов элементов и порядка итераций, что особенно важно в параллельно Программирование. Это мое мнение эта итерация, полагающаяся на порядок, не должна использоватьforeachдля лупинга.
если вы находитесь на .NET 3.5 вы можете сделать это:
IEnumerable<int> enumerableThing = ...; foreach (var x in enumerableThing.Reverse())это не очень эффективно, так как он должен в основном проходить через перечислитель вперед, помещая все в стек, а затем выталкивает все обратно в обратном порядке.
если у вас есть непосредственно индексируемая коллекция (например, IList), вы обязательно должны использовать
forвместо петли.если вы находитесь на .NET 2.0 и не можете использовать цикл for (т. е. у вас просто есть IEnumerable), вам просто нужно будет написать ваша собственная обратная функция. Это должно работать:
static IEnumerable<T> Reverse<T>(IEnumerable<T> input) { return new Stack<T>(input); }Это зависит от некоторого поведения, которое, возможно, не так очевидно. Когда вы передаете IEnumerable конструктору стека, он будет перебирать его и вставлять элементы в стек. Когда вы затем повторяете стек, он выталкивает вещи обратно в обратном порядке.
этот и тот .Net 3.5 с
Reverse()метод расширения, очевидно, взорвется, если вы подадите ему IEnumerable, который никогда не перестанет возвращаться предметы.
как говорит 280Z28, для
IList<T>вы можете просто использовать индекс. Вы можете скрыть это в методе расширения:public static IEnumerable<T> FastReverse<T>(this IList<T> items) { for (int i = items.Count-1; i >= 0; i--) { yield return items[i]; } }это будет быстрее, чем
Enumerable.Reverse()который буферизует все данные в первую очередь. (Я не верюReverseесть ли какие-либо оптимизации применяются таким образом, чтоCount()делает.) Обратите внимание, что эта буферизация означает, что данные считываются полностью при первом запуске итерации, тогда какFastReverseбудет "видеть" любые изменения, внесенные в список во время итерации. (Он также сломается, если вы удалите несколько элементов между итерациями.)для общих последовательностей нет способа итерации в обратном порядке-последовательность может быть бесконечной, например:
public static IEnumerable<T> GetStringsOfIncreasingSize() { string ret = ""; while (true) { yield return ret; ret = ret + "x"; } }что бы вы ожидали, если бы попытались повторить это в обратном порядке?
перед использованием 'foreach' для итерации, переверните список методом' reverse':
myList.Reverse(); foreach( List listItem in myList) { Console.WriteLine(listItem); }
Если вы используете List
, вы также можете использовать этот код: List<string> list = new List<string>(); list.Add("1"); list.Add("2"); list.Add("3"); list.Reverse();Это метод, который пишет обратный список сам по себе.
Теперь foreach:
foreach(string s in list) { Console.WriteLine(s); }выход:
3 2 1
нет. ForEach просто перебирает коллекцию для каждого элемента, и порядок зависит от того, использует ли он IEnumerable или GetEnumerator().
Это возможно, если вы можете изменить код который реализует IEnumerable или IEnumerable (например, ваша собственная реализация IList).
создать итератор выполнение этой работы для вас, например, как следующая реализация через IEnumerable интерфейс (предполагая, что "элементы" - это поле списка в этом примере):
public IEnumerator<TObject> GetEnumerator() { for (var i = items.Count - 1; i >= 0; i--) { yield return items[i]; } } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }из-за этого ваш список будет повторен в обратном порядке через список.
просто подсказка: вы должны четко указать это особое поведение вашего списка в документации (еще лучше, выбрав самоописывающее имя класса, такое как Stack или Queue).
иногда у вас нет роскоши индексирования, или, возможно, вы хотите отменить результаты запроса Linq, или, возможно, вы не хотите изменять исходную коллекцию, если какой-либо из них верен, Linq может помочь вам.
метод расширения Linq с использованием анонимных типов с Linq Select для предоставления ключа сортировки для Linq OrderByDescending;
public static IEnumerable<T> Invert<T>(this IEnumerable<T> source) { var transform = source.Select( (o, i) => new { Index = i, Object = o }); return transform.OrderByDescending(o => o.Index) .Select(o => o.Object); }использование:
var eable = new[]{ "a", "b", "c" }; foreach(var o in eable.Invert()) { Console.WriteLine(o); } // "c", "b", "a"Он называется "инвертировать", потому что он является синонимом "обратного" и позволяет неоднозначность со списком обратной реализации.
некоторые диапазоны коллекции тоже можно поменять местами, начиная с Int32.MinValue и Int32.MaxValue находятся вне диапазона любого типа индекса коллекции, мы можем использовать их для процесса заказа; если индекс элемента ниже заданного диапазона, он присваивается Int32.MaxValue, чтобы его порядок не менялся при использовании OrderByDescending, аналогично будут назначены элементы с индексом больше заданного диапазона Типа int32.MinValue, так что они появляются в конце процесса заказа. Всем элементам в пределах заданного диапазона присваивается их нормальный индекс и соответственно реверсируются.
public static IEnumerable<T> Invert<T>(this IEnumerable<T> source, int index, int count) { var transform = source.Select( (o, i) => new { Index = i < index ? Int32.MaxValue : i >= index + count ? Int32.MinValue : i, Object = o }); return transform.OrderByDescending(o => o.Index) .Select(o => o.Object); }использование:
var eable = new[]{ "a", "b", "c", "d" }; foreach(var o in eable.Invert(1, 2)) { Console.WriteLine(o); } // "a", "c", "b", "d"Я не уверен в производительности этих реализаций Linq по сравнению с использованием временного списка для обертывания коллекции для реверсирования.
на момент написания статьи я не знал о собственной обратной реализации Linq, тем не менее, было весело работать над этим из. https://msdn.microsoft.com/en-us/library/vstudio/bb358497 (v=vs. 100). aspx
разработка slighty на хороший ответ от Джон Скит, это может быть универсальным:
public static IEnumerable<T> Directional<T>(this IList<T> items, bool Forwards) { if (Forwards) foreach (T item in items) yield return item; else for (int i = items.Count-1; 0<=i; i--) yield return items[i]; }а затем использовать как
foreach (var item in myList.Directional(forwardsCondition)) { . . }
я использовал этот код, который работал
if (element.HasAttributes) { foreach(var attr in element.Attributes().Reverse()) { if (depth > 1) { elements_upper_hierarchy_text = ""; foreach (var ancest in element.Ancestors().Reverse()) { elements_upper_hierarchy_text += ancest.Name + "_"; }// foreach(var ancest in element.Ancestors()) }//if (depth > 1) xml_taglist_report += " " + depth + " " + elements_upper_hierarchy_text+ element.Name + "_" + attr.Name +"(" + attr.Name +")" + " = " + attr.Value + "\r\n"; }// foreach(var attr in element.Attributes().Reverse()) }// if (element.HasAttributes) {
это работает довольно хорошо
List<string> list = new List<string>(); list.Add("Hello"); list.Add("Who"); list.Add("Are"); list.Add("You"); foreach (String s in list) { Console.WriteLine(list[list.Count - list.IndexOf(s) - 1]); }
Comments