Mat*_*lls 137
如果您使用的是.NET 3.5,则可以执行以下操作:
IEnumerable<int> enumerableThing = ...;
foreach (var x in enumerableThing.Reverse())
Run Code Online (Sandbox Code Playgroud)
它不是非常有效,因为它必须基本上通过枚举器转发将所有内容放在堆栈上然后以相反的顺序将所有内容弹出.
如果你有一个可直接索引的集合(例如IList),你肯定应该使用for循环.
如果你使用的是.NET 2.0并且不能使用for循环(即你只有一个IEnumerable),那么你只需要编写自己的Reverse函数.这应该工作:
static IEnumerable<T> Reverse<T>(IEnumerable<T> input)
{
return new Stack<T>(input);
}
Run Code Online (Sandbox Code Playgroud)
这依赖于一些可能不那么明显的行为.当您将IEnumerable传递给堆栈构造函数时,它将遍历它并将项目推送到堆栈.然后当你遍历堆栈时,它会以相反的顺序弹出一些东西.
Reverse()如果你提供一个永远不会停止返回项目的IEnumerable,这个和.NET 3.5 扩展方法显然会爆炸.
Sam*_*ell 78
使用列表(直接索引)时,不能像使用for循环那样有效.
编辑:通常意味着,当您能够使用for循环时,它可能是此任务的正确方法.另外,对于按foreach顺序实现的内容,构造本身是为了表达独立于元素索引和迭代顺序的循环而构建的,这在并行编程中尤为重要.这是我的观点是迭代依托为了不应该使用foreach的循环.
Jon*_*eet 50
正如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];
}
}
Run Code Online (Sandbox Code Playgroud)
这将比Enumerable.Reverse()首先缓冲所有数据的速度更快.(我不相信Reverse有任何优化应用方式Count().)请注意,此缓冲意味着在您第一次开始迭代时完全读取数据,而在迭代时FastReverse将"看到"对列表所做的任何更改.(如果在迭代之间删除多个项目,它也会中断.)
对于一般序列,没有办法反向迭代 - 序列可能是无限的,例如:
public static IEnumerable<T> GetStringsOfIncreasingSize()
{
string ret = "";
while (true)
{
yield return ret;
ret = ret + "x";
}
}
Run Code Online (Sandbox Code Playgroud)
如果你试图反过来迭代,你会发生什么?
Pre*_*rem 11
在使用'foreach'进行迭代之前,请通过'reverse'方法反转列表:
myList.Reverse();
foreach( List listItem in myList)
{
Console.WriteLine(listItem);
}
Run Code Online (Sandbox Code Playgroud)
小智 5
如果您使用 List<T>,您还可以使用以下代码:
List<string> list = new List<string>();
list.Add("1");
list.Add("2");
list.Add("3");
list.Reverse();
Run Code Online (Sandbox Code Playgroud)
这是一种将列表本身反向写入的方法。
现在foreach:
foreach(string s in list)
{
Console.WriteLine(s);
}
Run Code Online (Sandbox Code Playgroud)
输出是:
3
2
1
Run Code Online (Sandbox Code Playgroud)
有时,您可能没有足够的索引编制能力,或者您想要反转Linq查询的结果,或者您可能不想修改源集合,如果其中任何一个都是正确的,Linq可以为您提供帮助。
一种使用匿名类型和Linq Select来为Linq OrderByDescending提供排序键的Linq扩展方法。
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);
}
Run Code Online (Sandbox Code Playgroud)
用法:
var eable = new[]{ "a", "b", "c" };
foreach(var o in eable.Invert())
{
Console.WriteLine(o);
}
// "c", "b", "a"
Run Code Online (Sandbox Code Playgroud)
它被称为“反转”,因为它与“反向”同义,并且可以实现“列表反向”实现的歧义。
也可以反转集合的某些范围,因为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);
}
Run Code Online (Sandbox Code Playgroud)
用法:
var eable = new[]{ "a", "b", "c", "d" };
foreach(var o in eable.Invert(1, 2))
{
Console.WriteLine(o);
}
// "a", "c", "b", "d"
Run Code Online (Sandbox Code Playgroud)
我不确定这些Linq实现是否会对性能产生影响,而不是使用临时List来包装要反转的集合。
在撰写本文时,我还不知道Linq自己的Reverse实现,但解决这个问题还是很有趣的。 https://msdn.microsoft.com/zh-CN/library/vstudio/bb358497(v=vs.100).aspx
稍微详细阐述乔恩·斯基特(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];
}
Run Code Online (Sandbox Code Playgroud)
然后用作
foreach (var item in myList.Directional(forwardsCondition)) {
.
.
}
Run Code Online (Sandbox Code Playgroud)