C# 可以通过foreach向后迭代吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1211608/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Possible to iterate backwards through a foreach?
提问by JL.
I know I could use a for
statement and achieve the same effect, but can I loop backwards through a foreach
loop in C#?
我知道我可以使用for
语句并达到相同的效果,但是我可以通过foreach
C# 中的循环向后循环吗?
采纳答案by Sam Harwell
When working with a list (direct indexing), you cannot do it as efficiently as using a for
loop.
使用列表(直接索引)时,不能像使用for
循环那样高效。
Edit: Which generally means, when you are ableto use a for
loop, it's likely the correct method for this task. Plus, for as much as foreach
is implemented in-order, the construct itself is built for expressing loops that are independent of element indexes and iteration order, which is particularly important in parallel programming. It is my opinionthat iteration relying on order should not use foreach
for looping.
编辑:这通常意味着,当您能够使用for
循环时,它可能是此任务的正确方法。此外,就按foreach
顺序实现的程度而言,构造本身是为表达独立于元素索引和迭代顺序的循环而构建的,这在并行编程中尤为重要。这是我的观点是迭代依托为了不应该使用foreach
的循环。
回答by Matt Howells
If you are on .NET 3.5 you can do this:
如果您使用 .NET 3.5,您可以这样做:
IEnumerable<int> enumerableThing = ...;
foreach (var x in enumerableThing.Reverse())
It isn't very efficient as it has to basically go through the enumerator forwards putting everything on a stack then pops everything back out in reverse order.
它不是很有效,因为它必须基本上通过枚举器向前将所有内容放在堆栈上,然后以相反的顺序弹出所有内容。
If you have a directly-indexable collection (e.g. IList) you should definitely use a for
loop instead.
如果您有一个可直接索引的集合(例如 IList),您绝对应该使用for
循环来代替。
If you are on .NET 2.0 and cannot use a for loop (i.e. you just have an IEnumerable) then you will just have to write your own Reverse function. This should work:
如果您使用 .NET 2.0 并且不能使用 for 循环(即您只有一个 IEnumerable),那么您只需编写自己的 Reverse 函数。这应该有效:
static IEnumerable<T> Reverse<T>(IEnumerable<T> input)
{
return new Stack<T>(input);
}
This relies on some behaviour which is perhaps not that obvious. When you pass in an IEnumerable to the stack constructor it will iterate through it and push the items onto the stack. When you then iterate through the stack it pops things back out in reverse order.
这依赖于一些可能不那么明显的行为。当您将 IEnumerable 传递给堆栈构造函数时,它将遍历它并将项目推入堆栈。当您然后遍历堆栈时,它会以相反的顺序弹出内容。
This and the .NET 3.5 Reverse()
extension method will obviously blow up if you feed it an IEnumerable which never stops returning items.
Reverse()
如果您向它提供一个永不停止返回项目的 IEnumerable,那么这个和 .NET 3.5扩展方法显然会爆炸。
回答by Josip Medved
No. ForEach just iterates through collection for each item and order depends whether it uses IEnumerable or GetEnumerator().
不。ForEach 只是遍历每个项目的集合,顺序取决于它是使用 IEnumerable 还是 GetEnumerator()。
回答by Jon Skeet
As 280Z28 says, for an IList<T>
you can just use the index. You could hide this in an extension method:
正如 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];
}
}
This will be faster than Enumerable.Reverse()
which buffers all the data first. (I don't believe Reverse
has any optimisations applied in the way that Count()
does.) Note that this buffering means that the data is read completely when you first start iterating, whereas FastReverse
will "see" any changes made to the list while you iterate. (It will also break if you remove multiple items between iterations.)
这将比Enumerable.Reverse()
首先缓冲所有数据更快。(我认为没有Reverse
以这种方式应用任何优化Count()
。)请注意,这种缓冲意味着在您第一次开始迭代时会完全读取数据,而在您迭代时FastReverse
将“看到”对列表所做的任何更改。(如果您在迭代之间删除多个项目,它也会中断。)
For general sequences, there's no way of iterating in reverse - the sequence could be infinite, for example:
对于一般序列,无法反向迭代 - 序列可能是无限的,例如:
public static IEnumerable<T> GetStringsOfIncreasingSize()
{
string ret = "";
while (true)
{
yield return ret;
ret = ret + "x";
}
}
What would you expect to happen if you tried to iterate over that in reverse?
如果您尝试反向迭代,您会期望发生什么?
回答by Mc_Topaz
This works pretty well
这很好用
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]);
}
回答by Beachwalker
It is possible if you can change the collection codethat implements IEnumerable or IEnumerable (e.g. your own implementation of IList).
如果您可以更改实现 IEnumerable 或 IEnumerable的集合代码(例如您自己的 IList 实现),则是可能的。
Create an Iteratordoing this job for you, for example like the following implementation through the IEnumerableinterface (assuming 'items' is a List field in this sample):
创建一个Iterator为您完成这项工作,例如通过IEnumerable接口实现以下实现(假设“items”是本示例中的 List 字段):
public IEnumerator<TObject> GetEnumerator()
{
for (var i = items.Count - 1; i >= 0; i--)
{
yield return items[i];
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
Because of this your List will iterate in reverse order through your list.
因此,您的列表将以相反的顺序遍历您的列表。
Just a hint: You should clearly state this special behaviour of your list within the documentation (even better by choosing a self-explaining class name like Stack or Queue, too).
只是一个提示:您应该在文档中清楚地说明您的列表的这种特殊行为(通过选择一个不言自明的类名,如 Stack 或 Queue,甚至更好)。
回答by th3s0urc3
If you use a List<T>, you can also use this code:
如果您使用 List<T>,您还可以使用以下代码:
List<string> list = new List<string>();
list.Add("1");
list.Add("2");
list.Add("3");
list.Reverse();
This is a method that write the list reverse in itself.
这是一种将列表本身反向写入的方法。
Now the foreach:
现在foreach:
foreach(string s in list)
{
Console.WriteLine(s);
}
The output is:
输出是:
3
2
1
回答by Prem
Before using 'foreach' for iteration, reverse the list by the 'reverse' method:
在使用 'foreach' 进行迭代之前,通过 'reverse' 方法反转列表:
myList.Reverse();
foreach( List listItem in myList)
{
Console.WriteLine(listItem);
}
回答by Vorspire
Sometimes you don't have the luxury of indexing, or perhaps you want to reverse the results of a Linq query, or maybe you don't want to modify the source collection, if any of these are true, Linq can help you.
有时您没有索引的奢侈,或者您可能想要反转 Linq 查询的结果,或者您可能不想修改源集合,如果其中任何一个是真的,Linq 可以帮助您。
A Linq extension method using anonymous types with Linq Select to provide a sorting key for Linq OrderByDescending;
使用匿名类型和 Linq Select 的 Linq 扩展方法,为 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);
}
Usage:
用法:
var eable = new[]{ "a", "b", "c" };
foreach(var o in eable.Invert())
{
Console.WriteLine(o);
}
// "c", "b", "a"
It is named "Invert" because it is synonymous with "Reverse" and enables disambiguation with the List Reverse implementation.
它被命名为“Invert”,因为它是“Reverse”的同义词,并且可以通过 List Reverse 实现消除歧义。
It is possible to reverse certain ranges of a collection too, since Int32.MinValue and Int32.MaxValue are out of the range of any kind of collection index, we can leverage them for the ordering process; if an element index is below the given range, it is assigned Int32.MaxValue so that its order doesn't change when using OrderByDescending, similarly, elements at an index greater than the given range, will be assigned Int32.MinValue, so that they appear to the end of the ordering process. All elements within the given range are assigned their normal index and are reversed accordingly.
也可以反转集合的某些范围,因为 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);
}
Usage:
用法:
var eable = new[]{ "a", "b", "c", "d" };
foreach(var o in eable.Invert(1, 2))
{
Console.WriteLine(o);
}
// "a", "c", "b", "d"
I'm not sure of the performance hits of these Linq implementations versus using a temporary List to wrap a collection for reversing.
我不确定这些 Linq 实现与使用临时 List 包装集合以进行反转相比的性能影响。
At time of writing, I was not aware of Linq's own Reverse implementation, still, it was fun working this out. https://msdn.microsoft.com/en-us/library/vstudio/bb358497(v=vs.100).aspx
在撰写本文时,我并不知道 Linq 自己的 Reverse 实现,但解决这个问题仍然很有趣。 https://msdn.microsoft.com/en-us/library/vstudio/bb358497(v=vs.100).aspx
回答by Sanjoy Nath
I have used this code which worked
我已经使用了这个有效的代码
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) {