我知道我可以使用for
语句并达到相同的效果,但是我可以在C#中循环回foreach
循环吗?
答案 0 :(得分:130)
如果您使用的是.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传递给堆栈构造函数时,它将遍历它并将项目推送到堆栈。然后,当您遍历堆栈时,它会以相反的顺序将事物弹出。
如果你提供一个永远不会停止返回项目的IEnumerable,这个和.NET 3.5 Reverse()
扩展方法显然会爆炸。
答案 1 :(得分:72)
使用列表(直接索引)时,不能像使用for
循环一样有效。
编辑:这通常意味着,当您能够使用for
循环时,它可能是执行此任务的正确方法。另外,对于按顺序实现foreach
而言,构造本身是为了表达独立于元素索引和迭代顺序的循环而构建的,这在parallel programming中尤为重要。 我的观点依赖于订单的迭代不应使用foreach
进行循环。
答案 2 :(得分:48)
正如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";
}
}
如果你试图反过来反复思考,你会发生什么?
答案 3 :(得分:8)
在使用&#39; foreach&#39;对于迭代,通过&#39;反向&#39;反转列表。方法:
myList.Reverse();
foreach( List listItem in myList)
{
Console.WriteLine(listItem);
}
答案 4 :(得分:4)
如果您使用列表&lt; T&gt;,您还可以使用以下代码:
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
答案 5 :(得分:4)
有时你没有索引的奢侈,或者你想要反转Linq查询的结果,或者你可能不想修改源集合,如果其中任何一个都是真的,Linq可以帮助你。
使用带有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);
}
用法:
var eable = new[]{ "a", "b", "c" };
foreach(var o in eable.Invert())
{
Console.WriteLine(o);
}
// "c", "b", "a"
它被命名为“Invert”,因为它与“Reverse”同义,并且可以通过List Reverse实现消除歧义。
也可以反转集合的某些范围,因为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实现的性能命中率,而不是使用临时List来包装用于反转的集合。
在撰写本文时,我并不知道Linq自己的Reverse实现,但仍然很有趣。 https://msdn.microsoft.com/en-us/library/vstudio/bb358497(v=vs.100).aspx
答案 6 :(得分:2)
没有。 ForEach只是遍历每个项目的集合,顺序取决于它是使用IEnumerable还是GetEnumerator()。
答案 7 :(得分:2)
如果您可以更改实现IEnumerable或IEnumerable的集合代码(例如您自己的IList实现),那么是可能的。
创建一个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();
}
因此,您的列表将以相反的顺序在您的列表中迭代。
只是一个提示:你应该在文档中清楚地说明列表的这种特殊行为(甚至更好地选择自我解释的类名,如Stack或Queue)。
答案 8 :(得分:0)
详细说明Jon Skeet给出的好答案,这可能是多方面的:
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)) {
.
.
}
答案 9 :(得分:-1)
我使用了这个有效的代码
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) {
答案 10 :(得分:-8)
这很好用
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]);
}