I need to move backwards through an array, so I have code like this:
我需要向后移动一个数组,所以我有如下代码:
for (int i = myArray.Length - 1; i >= 0; i--)
{
// Do something
myArray[i] = 42;
}
Is there a better way of doing this?
有更好的方法吗?
Update: I was hoping that maybe C# had some built-in mechanism for this like:
更新:我希望c#有一些内置的机制,比如:
foreachbackwards (int i in myArray)
{
// so easy
}
Update 2: There are better ways. Rune takes the prize with:
更新2:有更好的方法。符文以:
for (int i = myArray.Length; i-- > 0; )
{
//do something
}
//or
for (int i = myArray.Length; i --> 0; )
{
// do something
}
which looks even better in regular C (thanks to Twotymz):
在普通的C中看起来更好(多亏了两个tymz):
for (int i = lengthOfArray; i--; )
{
//do something
}
15 个解决方案
#1
116
While admittedly a bit obscure, I would say that the most typographically pleasing way of doing this is
虽然我承认这有点晦涩难懂,但我想说的是,这样做最让人赏心悦目的方式是
for (int i = myArray.Length; i --> 0; )
{
//do something
}
#2
106
In C++ you basicially have the choice between iterating using iterators, or indices. Depending on whether you have a plain array, or a std::vector
, you use different techniques.
在c++中,您基本上可以选择使用迭代器进行迭代,还是使用索引。取决于您是否有一个普通数组或std::vector,您使用了不同的技术。
Using std::vector
Using iterators
C++ allows you to do this using std::reverse_iterator:
c++允许您使用std:::reverse_iterator:
for(std::vector<T>::reverse_iterator it = v.rbegin(); it != v.rend(); ++it) {
/* std::cout << *it; ... */
}
Using indices
The unsigned integral type returned by std::vector<T>::size
is not always std::size_t
. It can be greater or less. This is crucial for the loop to work.
std返回的无符号整数类型::vector
for(std::vector<int>::size_type i = someVector.size() - 1;
i != (std::vector<int>::size_type) -1; i--) {
/* std::cout << someVector[i]; ... */
}
It works, since unsigned integral types values are defined by means of modulo their count of bits. Thus, if you are setting -N
, you end up at (2 ^ BIT_SIZE) -N
它是有效的,因为无符号积分类型的值是通过它们的位元数的模来定义的。因此,如果你设置- n,最终在(2 ^ BIT_SIZE)- n
Using Arrays
Using iterators
We are using std::reverse_iterator
to do the iterating.
我们使用std::reverse_iterator进行迭代。
for(std::reverse_iterator<element_type*> it(a + sizeof a / sizeof *a), itb(a);
it != itb;
++it) {
/* std::cout << *it; .... */
}
Using indices
We can safely use std::size_t
here, as opposed to above, since sizeof
always returns std::size_t
by definition.
我们可以在这里安全地使用std::size_t,而不是上面,因为根据定义,sizeof总是返回std::size_t。
for(std::size_t i = (sizeof a / sizeof *a) - 1; i != (std::size_t) -1; i--) {
/* std::cout << a[i]; ... */
}
Avoiding pitfalls with sizeof applied to pointers
Actually the above way of determining the size of an array sucks. If a is actually a pointer instead of an array (which happens quite often, and beginners will confuse it), it will silently fail. A better way is to use the following, which will fail at compile time, if given a pointer:
实际上,上面确定数组大小的方法很糟糕。如果a实际上是一个指针,而不是一个数组(这种情况经常发生,初学者会把它弄糊涂),那么它将无声地失败。更好的方法是使用以下方法,如果给定一个指针,在编译时将会失败:
template<typename T, std::size_t N> char (& array_size(T(&)[N]) )[N];
It works by getting the size of the passed array first, and then declaring to return a reference to an array of type char of the same size. char
is defined to have sizeof
of: 1. So the returned array will have a sizeof
of: N * 1, which is what we are looking for, with only compile time evaluation and zero runtime overhead.
它首先获取所传递数组的大小,然后声明返回对相同大小的char类型数组的引用。char定义为sizeof: 1。因此返回的数组的大小为:N * 1,这就是我们要寻找的,只有编译时评估和零运行时开销。
Instead of doing
而不是做
(sizeof a / sizeof *a)
Change your code so that it now does
改变你的代码,这样它就可以了
(sizeof array_size(a))
#3
41
In C#, using Visual Studio 2005 or later, type 'forr' and hit [TAB] [TAB]. This will expand to a for
loop that goes backwards through a collection.
在c#中,使用Visual Studio 2005或更高版本,输入'forr'并单击[TAB] [TAB] [TAB]。这将扩展到一个for循环,该循环通过集合向后进行。
It's so easy to get wrong (at least for me), that I thought putting this snippet in would be a good idea.
很容易出错(至少对我来说),所以我认为把这段代码放到里面是个好主意。
That said, I like Array.Reverse()
/ Enumerable.Reverse()
and then iterate forwards better - they more clearly state intent.
这就是说,我喜欢Array.Reverse() / Enumerable.Reverse(),然后更好地迭代转发——它们更清楚地表示状态意图。
#4
23
I would always prefer clear code against 'typographically pleasing' code. Thus, I would always use :
我总是喜欢清晰的代码,而不是“排版美观”的代码。因此,我总是用:
for (int i = myArray.Length - 1; i >= 0; i--)
{
// Do something ...
}
You can consider it as the standard way to loop backwards.
Just my two cents...
您可以将它视为反向循环的标准方法。只是我两美分…
#5
15
In C# using Linq:
在c#中使用Linq:
foreach(var item in myArray.Reverse())
{
// do something
}
#6
10
That's definitely the best way for any array whose length is a signed integral type. For arrays whose lengths are an unsigned integral type (e.g. an std::vector
in C++), then you need to modify the end condition slightly:
对于任何长度为有符号整型的数组来说,这绝对是最好的方法。对于长度为无符号整型的数组(例如c++中的std::vector),则需要稍微修改结束条件:
for(size_t i = myArray.size() - 1; i != (size_t)-1; i--)
// blah
If you just said i >= 0
, this is always true for an unsigned integer, so the loop will be an infinite loop.
如果你说i >= 0,这对于无符号整数来说总是成立的,所以循环将是一个无限循环。
#7
4
Looks good to me. If the indexer was unsigned (uint etc), you might have to take that into account. Call me lazy, but in that (unsigned) case, I might just use a counter-variable:
我看起来很好。如果索引器是无符号的(uint等),您可能必须考虑到这一点。称之为懒惰,但在这种情况下(无符号),我可能只使用一个反变量:
uint pos = arr.Length;
for(uint i = 0; i < arr.Length ; i++)
{
arr[--pos] = 42;
}
(actually, even here you'd need to be careful of cases like arr.Length = uint.MaxValue... maybe a != somewhere... of course, that is a very unlikely case!)
(实际上,即使是在这里,你也需要小心像arr这样的情况。长度= uint.MaxValue……也许! =某个地方……当然,这是一个非常不可能的情况!
#8
4
In C I like to do this:
在C中,我喜欢这样做:
int i = myArray.Length;
while (i--) {
myArray[i] = 42;
}
C# example added by MusiGenesis:
c#示例由MusiGenesis添加:
{int i = myArray.Length; while (i-- > 0)
{
myArray[i] = 42;
}}
#9
3
The best way to do that in C++ is probably to use iterator (or better, range) adaptors, which will lazily transform the sequence as it is being traversed.
在c++中,最好的方法是使用迭代器(或更好的,范围)适配器,它将在遍历过程中延迟地转换序列。
Basically,
基本上,
vector<value_type> range;
foreach(value_type v, range | reversed)
cout << v;
Displays the range "range" (here, it's empty, but i'm fairly sure you can add elements yourself) in reverse order. Of course simply iterating the range is not much use, but passing that new range to algorithms and stuff is pretty cool.
显示范围“range”(在这里,它是空的,但我确信您可以自己添加元素),并以相反的顺序显示。当然,简单地重复这个范围并不是很有用,但是将这个新的范围传递给算法和其他东西是很酷的。
This mechanism can also be used for much more powerful uses:
这种机制也可用于更强大的用途:
range | transformed(f) | filtered(p) | reversed
Will lazily compute the range "range", where function "f" is applied to all elements, elements for which "p" is not true are removed, and finally the resulting range is reversed.
将延迟计算范围“range”,其中函数f应用于所有元素,删除不为p的元素,最终得到的范围颠倒。
Pipe syntax is the most readable IMO, given it's infix. The Boost.Range library update pending review implements this, but it's pretty simple to do it yourself also. It's even more cool with a lambda DSEL to generate the function f and the predicate p in-line.
管道语法是最有可读性的,因为它是中缀的。的提振。Range library update pending review实现了这一点,但是你自己也可以很简单地完成它。用一个DSEL来生成函数f和谓词p更酷。
#10
1
// this is how I always do it
for (i = n; --i >= 0;){
...
}
#11
1
I prefer a while loop. It's more clear to me than decrementing i
in the condition of a for loop
我喜欢用while循环。对于我来说,它比在for循环条件下对i进行递减更清晰
int i = arrayLength;
while(i)
{
i--;
//do something with array[i]
}
#12
0
I'd use the code in the original question, but if you really wanted to use foreach and have an integer index in C#:
我将使用原始问题中的代码,但是如果您真的想使用foreach并在c#中有一个整数索引:
foreach (int i in Enumerable.Range(0, myArray.Length).Reverse())
{
myArray[i] = 42;
}
#13
0
I'm not sure I see why any of the alternatives is better, if goodness includes clarity or maintainability.
我不确定为什么所有的选择都更好,如果优点包括清晰性或可维护性的话。
#14
-1
I'm going to try answering my own question here, but I don't really like this, either:
我想在这里回答我自己的问题,但我也不太喜欢这个问题:
for (int i = 0; i < myArray.Length; i++)
{
int iBackwards = myArray.Length - 1 - i; // ugh
myArray[iBackwards] = 666;
}
#15
-4
NOTE: This post ended up being far more detailed and therefore off topic, I apologize.
注意:这篇文章的内容要详细得多,所以我道歉。
That being said my peers read it and believe it is valuable 'somewhere'. This thread is not the place. I would appreciate your feedback on where this should go (I am new to the site).
尽管如此,我的同行们还是读了这本书,并相信它在“某个地方”是有价值的。这条线不是地方。如果您能给我一些建议,我将不胜感激。
Anyway this is the C# version in .NET 3.5 which is amazing in that it works on any collection type using the defined semantics. This is a default measure (reuse!) not performance or CPU cycle minimization in most common dev scenario although that never seems to be what happens in the real world (premature optimization).
无论如何,这是。net 3.5中的c#版本,它在使用定义的语义处理任何集合类型时都非常出色。在大多数常见的开发场景中,这是一个默认的度量(重用!),而不是性能或CPU周期最小化,尽管在现实世界中似乎从未发生过这种情况(过早的优化)。
*** Extension method working over any collection type and taking an action delegate expecting a single value of the type, all executed over each item in reverse **
***扩展方法可以处理任何集合类型,并获取一个动作委托,期望该类型的单个值,所有这些都以反向**方式在每个项上执行
Requres 3.5:
要求当3.5:
public static void PerformOverReversed<T>(this IEnumerable<T> sequenceToReverse, Action<T> doForEachReversed)
{
foreach (var contextItem in sequenceToReverse.Reverse())
doForEachReversed(contextItem);
}
Older .NET versions or do you want to understand Linq internals better? Read on.. Or not..
较老的。net版本,还是您希望更好地理解Linq的内部内容?继续阅读…不信. .
ASSUMPTION: In the .NET type system the Array type inherits from the IEnumerable interface (not the generic IEnumerable only IEnumerable).
假设:在. net类型系统中,数组类型继承自IEnumerable接口(不是通用的IEnumerable接口,只能是IEnumerable)。
This is all you need to iterate from beginning to end, however you want to move in the opposite direction. As IEnumerable works on Array of type 'object' any type is valid,
这是您从头到尾迭代的全部内容,但是您想要向相反的方向移动。当IEnumerable对‘object’类型的数组起作用时,任何类型都是有效的,
CRITICAL MEASURE: We assume if you can process any sequence in reverse order that is 'better' then only being able to do it on integers.
关键度量:我们假设,如果你可以按照“更好”的顺序来处理任何序列,那么只有在整数上才能这样做。
Solution a for .NET CLR 2.0-3.0:
.NET CLR 2.0-3.0的解决方案a:
Description: We will accept any IEnumerable implementing instance with the mandate that each instance it contains is of the same type. So if we recieve an array the entire array contains instances of type X. If any other instances are of a type !=X an exception is thrown:
说明:我们将接受任何IEnumerable实现实例,它所包含的每个实例都具有相同的类型。因此,如果我们接收到一个数组,那么整个数组都包含X类型的实例。
A singleton service:
一个单例服务:
public class ReverserService { private ReverserService() { }
public class ReverserService {private ReverserService()}
/// <summary>
/// Most importantly uses yield command for efficiency
/// </summary>
/// <param name="enumerableInstance"></param>
/// <returns></returns>
public static IEnumerable ToReveresed(IEnumerable enumerableInstance)
{
if (enumerableInstance == null)
{
throw new ArgumentNullException("enumerableInstance");
}
// First we need to move forwarad and create a temp
// copy of a type that allows us to move backwards
// We can use ArrayList for this as the concrete
// type
IList reversedEnumerable = new ArrayList();
IEnumerator tempEnumerator = enumerableInstance.GetEnumerator();
while (tempEnumerator.MoveNext())
{
reversedEnumerable.Add(tempEnumerator.Current);
}
// Now we do the standard reverse over this using yield to return
// the result
// NOTE: This is an immutable result by design. That is
// a design goal for this simple question as well as most other set related
// requirements, which is why Linq results are immutable for example
// In fact this is foundational code to understand Linq
for (var i = reversedEnumerable.Count - 1; i >= 0; i--)
{
yield return reversedEnumerable[i];
}
}
}
public static class ExtensionMethods
{
public static IEnumerable ToReveresed(this IEnumerable enumerableInstance)
{
return ReverserService.ToReveresed(enumerableInstance);
}
}
[TestFixture] public class Testing123 {
[TestFixture]
/// <summary>
/// .NET 1.1 CLR
/// </summary>
[Test]
public void Tester_fornet_1_dot_1()
{
const int initialSize = 1000;
// Create the baseline data
int[] myArray = new int[initialSize];
for (var i = 0; i < initialSize; i++)
{
myArray[i] = i + 1;
}
IEnumerable _revered = ReverserService.ToReveresed(myArray);
Assert.IsTrue(TestAndGetResult(_revered).Equals(1000));
}
[Test]
public void tester_why_this_is_good()
{
ArrayList names = new ArrayList();
names.Add("Jim");
names.Add("Bob");
names.Add("Eric");
names.Add("Sam");
IEnumerable _revered = ReverserService.ToReveresed(names);
Assert.IsTrue(TestAndGetResult(_revered).Equals("Sam"));
}
[Test]
public void tester_extension_method()
{
// Extension Methods No Linq (Linq does this for you as I will show)
var enumerableOfInt = Enumerable.Range(1, 1000);
// Use Extension Method - which simply wraps older clr code
IEnumerable _revered = enumerableOfInt.ToReveresed();
Assert.IsTrue(TestAndGetResult(_revered).Equals(1000));
}
[Test]
public void tester_linq_3_dot_5_clr()
{
// Extension Methods No Linq (Linq does this for you as I will show)
IEnumerable enumerableOfInt = Enumerable.Range(1, 1000);
// Reverse is Linq (which is are extension methods off IEnumerable<T>
// Note you must case IEnumerable (non generic) using OfType or Cast
IEnumerable _revered = enumerableOfInt.Cast<int>().Reverse();
Assert.IsTrue(TestAndGetResult(_revered).Equals(1000));
}
[Test]
public void tester_final_and_recommended_colution()
{
var enumerableOfInt = Enumerable.Range(1, 1000);
enumerableOfInt.PerformOverReversed(i => Debug.WriteLine(i));
}
private static object TestAndGetResult(IEnumerable enumerableIn)
{
// IEnumerable x = ReverserService.ToReveresed(names);
Assert.IsTrue(enumerableIn != null);
IEnumerator _test = enumerableIn.GetEnumerator();
// Move to first
Assert.IsTrue(_test.MoveNext());
return _test.Current;
}
}
#1
116
While admittedly a bit obscure, I would say that the most typographically pleasing way of doing this is
虽然我承认这有点晦涩难懂,但我想说的是,这样做最让人赏心悦目的方式是
for (int i = myArray.Length; i --> 0; )
{
//do something
}
#2
106
In C++ you basicially have the choice between iterating using iterators, or indices. Depending on whether you have a plain array, or a std::vector
, you use different techniques.
在c++中,您基本上可以选择使用迭代器进行迭代,还是使用索引。取决于您是否有一个普通数组或std::vector,您使用了不同的技术。
Using std::vector
Using iterators
C++ allows you to do this using std::reverse_iterator:
c++允许您使用std:::reverse_iterator:
for(std::vector<T>::reverse_iterator it = v.rbegin(); it != v.rend(); ++it) {
/* std::cout << *it; ... */
}
Using indices
The unsigned integral type returned by std::vector<T>::size
is not always std::size_t
. It can be greater or less. This is crucial for the loop to work.
std返回的无符号整数类型::vector
for(std::vector<int>::size_type i = someVector.size() - 1;
i != (std::vector<int>::size_type) -1; i--) {
/* std::cout << someVector[i]; ... */
}
It works, since unsigned integral types values are defined by means of modulo their count of bits. Thus, if you are setting -N
, you end up at (2 ^ BIT_SIZE) -N
它是有效的,因为无符号积分类型的值是通过它们的位元数的模来定义的。因此,如果你设置- n,最终在(2 ^ BIT_SIZE)- n
Using Arrays
Using iterators
We are using std::reverse_iterator
to do the iterating.
我们使用std::reverse_iterator进行迭代。
for(std::reverse_iterator<element_type*> it(a + sizeof a / sizeof *a), itb(a);
it != itb;
++it) {
/* std::cout << *it; .... */
}
Using indices
We can safely use std::size_t
here, as opposed to above, since sizeof
always returns std::size_t
by definition.
我们可以在这里安全地使用std::size_t,而不是上面,因为根据定义,sizeof总是返回std::size_t。
for(std::size_t i = (sizeof a / sizeof *a) - 1; i != (std::size_t) -1; i--) {
/* std::cout << a[i]; ... */
}
Avoiding pitfalls with sizeof applied to pointers
Actually the above way of determining the size of an array sucks. If a is actually a pointer instead of an array (which happens quite often, and beginners will confuse it), it will silently fail. A better way is to use the following, which will fail at compile time, if given a pointer:
实际上,上面确定数组大小的方法很糟糕。如果a实际上是一个指针,而不是一个数组(这种情况经常发生,初学者会把它弄糊涂),那么它将无声地失败。更好的方法是使用以下方法,如果给定一个指针,在编译时将会失败:
template<typename T, std::size_t N> char (& array_size(T(&)[N]) )[N];
It works by getting the size of the passed array first, and then declaring to return a reference to an array of type char of the same size. char
is defined to have sizeof
of: 1. So the returned array will have a sizeof
of: N * 1, which is what we are looking for, with only compile time evaluation and zero runtime overhead.
它首先获取所传递数组的大小,然后声明返回对相同大小的char类型数组的引用。char定义为sizeof: 1。因此返回的数组的大小为:N * 1,这就是我们要寻找的,只有编译时评估和零运行时开销。
Instead of doing
而不是做
(sizeof a / sizeof *a)
Change your code so that it now does
改变你的代码,这样它就可以了
(sizeof array_size(a))
#3
41
In C#, using Visual Studio 2005 or later, type 'forr' and hit [TAB] [TAB]. This will expand to a for
loop that goes backwards through a collection.
在c#中,使用Visual Studio 2005或更高版本,输入'forr'并单击[TAB] [TAB] [TAB]。这将扩展到一个for循环,该循环通过集合向后进行。
It's so easy to get wrong (at least for me), that I thought putting this snippet in would be a good idea.
很容易出错(至少对我来说),所以我认为把这段代码放到里面是个好主意。
That said, I like Array.Reverse()
/ Enumerable.Reverse()
and then iterate forwards better - they more clearly state intent.
这就是说,我喜欢Array.Reverse() / Enumerable.Reverse(),然后更好地迭代转发——它们更清楚地表示状态意图。
#4
23
I would always prefer clear code against 'typographically pleasing' code. Thus, I would always use :
我总是喜欢清晰的代码,而不是“排版美观”的代码。因此,我总是用:
for (int i = myArray.Length - 1; i >= 0; i--)
{
// Do something ...
}
You can consider it as the standard way to loop backwards.
Just my two cents...
您可以将它视为反向循环的标准方法。只是我两美分…
#5
15
In C# using Linq:
在c#中使用Linq:
foreach(var item in myArray.Reverse())
{
// do something
}
#6
10
That's definitely the best way for any array whose length is a signed integral type. For arrays whose lengths are an unsigned integral type (e.g. an std::vector
in C++), then you need to modify the end condition slightly:
对于任何长度为有符号整型的数组来说,这绝对是最好的方法。对于长度为无符号整型的数组(例如c++中的std::vector),则需要稍微修改结束条件:
for(size_t i = myArray.size() - 1; i != (size_t)-1; i--)
// blah
If you just said i >= 0
, this is always true for an unsigned integer, so the loop will be an infinite loop.
如果你说i >= 0,这对于无符号整数来说总是成立的,所以循环将是一个无限循环。
#7
4
Looks good to me. If the indexer was unsigned (uint etc), you might have to take that into account. Call me lazy, but in that (unsigned) case, I might just use a counter-variable:
我看起来很好。如果索引器是无符号的(uint等),您可能必须考虑到这一点。称之为懒惰,但在这种情况下(无符号),我可能只使用一个反变量:
uint pos = arr.Length;
for(uint i = 0; i < arr.Length ; i++)
{
arr[--pos] = 42;
}
(actually, even here you'd need to be careful of cases like arr.Length = uint.MaxValue... maybe a != somewhere... of course, that is a very unlikely case!)
(实际上,即使是在这里,你也需要小心像arr这样的情况。长度= uint.MaxValue……也许! =某个地方……当然,这是一个非常不可能的情况!
#8
4
In C I like to do this:
在C中,我喜欢这样做:
int i = myArray.Length;
while (i--) {
myArray[i] = 42;
}
C# example added by MusiGenesis:
c#示例由MusiGenesis添加:
{int i = myArray.Length; while (i-- > 0)
{
myArray[i] = 42;
}}
#9
3
The best way to do that in C++ is probably to use iterator (or better, range) adaptors, which will lazily transform the sequence as it is being traversed.
在c++中,最好的方法是使用迭代器(或更好的,范围)适配器,它将在遍历过程中延迟地转换序列。
Basically,
基本上,
vector<value_type> range;
foreach(value_type v, range | reversed)
cout << v;
Displays the range "range" (here, it's empty, but i'm fairly sure you can add elements yourself) in reverse order. Of course simply iterating the range is not much use, but passing that new range to algorithms and stuff is pretty cool.
显示范围“range”(在这里,它是空的,但我确信您可以自己添加元素),并以相反的顺序显示。当然,简单地重复这个范围并不是很有用,但是将这个新的范围传递给算法和其他东西是很酷的。
This mechanism can also be used for much more powerful uses:
这种机制也可用于更强大的用途:
range | transformed(f) | filtered(p) | reversed
Will lazily compute the range "range", where function "f" is applied to all elements, elements for which "p" is not true are removed, and finally the resulting range is reversed.
将延迟计算范围“range”,其中函数f应用于所有元素,删除不为p的元素,最终得到的范围颠倒。
Pipe syntax is the most readable IMO, given it's infix. The Boost.Range library update pending review implements this, but it's pretty simple to do it yourself also. It's even more cool with a lambda DSEL to generate the function f and the predicate p in-line.
管道语法是最有可读性的,因为它是中缀的。的提振。Range library update pending review实现了这一点,但是你自己也可以很简单地完成它。用一个DSEL来生成函数f和谓词p更酷。
#10
1
// this is how I always do it
for (i = n; --i >= 0;){
...
}
#11
1
I prefer a while loop. It's more clear to me than decrementing i
in the condition of a for loop
我喜欢用while循环。对于我来说,它比在for循环条件下对i进行递减更清晰
int i = arrayLength;
while(i)
{
i--;
//do something with array[i]
}
#12
0
I'd use the code in the original question, but if you really wanted to use foreach and have an integer index in C#:
我将使用原始问题中的代码,但是如果您真的想使用foreach并在c#中有一个整数索引:
foreach (int i in Enumerable.Range(0, myArray.Length).Reverse())
{
myArray[i] = 42;
}
#13
0
I'm not sure I see why any of the alternatives is better, if goodness includes clarity or maintainability.
我不确定为什么所有的选择都更好,如果优点包括清晰性或可维护性的话。
#14
-1
I'm going to try answering my own question here, but I don't really like this, either:
我想在这里回答我自己的问题,但我也不太喜欢这个问题:
for (int i = 0; i < myArray.Length; i++)
{
int iBackwards = myArray.Length - 1 - i; // ugh
myArray[iBackwards] = 666;
}
#15
-4
NOTE: This post ended up being far more detailed and therefore off topic, I apologize.
注意:这篇文章的内容要详细得多,所以我道歉。
That being said my peers read it and believe it is valuable 'somewhere'. This thread is not the place. I would appreciate your feedback on where this should go (I am new to the site).
尽管如此,我的同行们还是读了这本书,并相信它在“某个地方”是有价值的。这条线不是地方。如果您能给我一些建议,我将不胜感激。
Anyway this is the C# version in .NET 3.5 which is amazing in that it works on any collection type using the defined semantics. This is a default measure (reuse!) not performance or CPU cycle minimization in most common dev scenario although that never seems to be what happens in the real world (premature optimization).
无论如何,这是。net 3.5中的c#版本,它在使用定义的语义处理任何集合类型时都非常出色。在大多数常见的开发场景中,这是一个默认的度量(重用!),而不是性能或CPU周期最小化,尽管在现实世界中似乎从未发生过这种情况(过早的优化)。
*** Extension method working over any collection type and taking an action delegate expecting a single value of the type, all executed over each item in reverse **
***扩展方法可以处理任何集合类型,并获取一个动作委托,期望该类型的单个值,所有这些都以反向**方式在每个项上执行
Requres 3.5:
要求当3.5:
public static void PerformOverReversed<T>(this IEnumerable<T> sequenceToReverse, Action<T> doForEachReversed)
{
foreach (var contextItem in sequenceToReverse.Reverse())
doForEachReversed(contextItem);
}
Older .NET versions or do you want to understand Linq internals better? Read on.. Or not..
较老的。net版本,还是您希望更好地理解Linq的内部内容?继续阅读…不信. .
ASSUMPTION: In the .NET type system the Array type inherits from the IEnumerable interface (not the generic IEnumerable only IEnumerable).
假设:在. net类型系统中,数组类型继承自IEnumerable接口(不是通用的IEnumerable接口,只能是IEnumerable)。
This is all you need to iterate from beginning to end, however you want to move in the opposite direction. As IEnumerable works on Array of type 'object' any type is valid,
这是您从头到尾迭代的全部内容,但是您想要向相反的方向移动。当IEnumerable对‘object’类型的数组起作用时,任何类型都是有效的,
CRITICAL MEASURE: We assume if you can process any sequence in reverse order that is 'better' then only being able to do it on integers.
关键度量:我们假设,如果你可以按照“更好”的顺序来处理任何序列,那么只有在整数上才能这样做。
Solution a for .NET CLR 2.0-3.0:
.NET CLR 2.0-3.0的解决方案a:
Description: We will accept any IEnumerable implementing instance with the mandate that each instance it contains is of the same type. So if we recieve an array the entire array contains instances of type X. If any other instances are of a type !=X an exception is thrown:
说明:我们将接受任何IEnumerable实现实例,它所包含的每个实例都具有相同的类型。因此,如果我们接收到一个数组,那么整个数组都包含X类型的实例。
A singleton service:
一个单例服务:
public class ReverserService { private ReverserService() { }
public class ReverserService {private ReverserService()}
/// <summary>
/// Most importantly uses yield command for efficiency
/// </summary>
/// <param name="enumerableInstance"></param>
/// <returns></returns>
public static IEnumerable ToReveresed(IEnumerable enumerableInstance)
{
if (enumerableInstance == null)
{
throw new ArgumentNullException("enumerableInstance");
}
// First we need to move forwarad and create a temp
// copy of a type that allows us to move backwards
// We can use ArrayList for this as the concrete
// type
IList reversedEnumerable = new ArrayList();
IEnumerator tempEnumerator = enumerableInstance.GetEnumerator();
while (tempEnumerator.MoveNext())
{
reversedEnumerable.Add(tempEnumerator.Current);
}
// Now we do the standard reverse over this using yield to return
// the result
// NOTE: This is an immutable result by design. That is
// a design goal for this simple question as well as most other set related
// requirements, which is why Linq results are immutable for example
// In fact this is foundational code to understand Linq
for (var i = reversedEnumerable.Count - 1; i >= 0; i--)
{
yield return reversedEnumerable[i];
}
}
}
public static class ExtensionMethods
{
public static IEnumerable ToReveresed(this IEnumerable enumerableInstance)
{
return ReverserService.ToReveresed(enumerableInstance);
}
}
[TestFixture] public class Testing123 {
[TestFixture]
/// <summary>
/// .NET 1.1 CLR
/// </summary>
[Test]
public void Tester_fornet_1_dot_1()
{
const int initialSize = 1000;
// Create the baseline data
int[] myArray = new int[initialSize];
for (var i = 0; i < initialSize; i++)
{
myArray[i] = i + 1;
}
IEnumerable _revered = ReverserService.ToReveresed(myArray);
Assert.IsTrue(TestAndGetResult(_revered).Equals(1000));
}
[Test]
public void tester_why_this_is_good()
{
ArrayList names = new ArrayList();
names.Add("Jim");
names.Add("Bob");
names.Add("Eric");
names.Add("Sam");
IEnumerable _revered = ReverserService.ToReveresed(names);
Assert.IsTrue(TestAndGetResult(_revered).Equals("Sam"));
}
[Test]
public void tester_extension_method()
{
// Extension Methods No Linq (Linq does this for you as I will show)
var enumerableOfInt = Enumerable.Range(1, 1000);
// Use Extension Method - which simply wraps older clr code
IEnumerable _revered = enumerableOfInt.ToReveresed();
Assert.IsTrue(TestAndGetResult(_revered).Equals(1000));
}
[Test]
public void tester_linq_3_dot_5_clr()
{
// Extension Methods No Linq (Linq does this for you as I will show)
IEnumerable enumerableOfInt = Enumerable.Range(1, 1000);
// Reverse is Linq (which is are extension methods off IEnumerable<T>
// Note you must case IEnumerable (non generic) using OfType or Cast
IEnumerable _revered = enumerableOfInt.Cast<int>().Reverse();
Assert.IsTrue(TestAndGetResult(_revered).Equals(1000));
}
[Test]
public void tester_final_and_recommended_colution()
{
var enumerableOfInt = Enumerable.Range(1, 1000);
enumerableOfInt.PerformOverReversed(i => Debug.WriteLine(i));
}
private static object TestAndGetResult(IEnumerable enumerableIn)
{
// IEnumerable x = ReverserService.ToReveresed(names);
Assert.IsTrue(enumerableIn != null);
IEnumerator _test = enumerableIn.GetEnumerator();
// Move to first
Assert.IsTrue(_test.MoveNext());
return _test.Current;
}
}