4

I have a List<T> that I want to be able to copy to an array backwards, meaning start from List.Count and copy maybe 5 items starting at the end of the list and working its way backwards. I could do this with a simple reverse for loop; however there is probably a faster/more efficient way of doing this so I thought I should ask. Can I use Array.Copy somehow?

Originally I was using a Queue as that pops it off in the correct order I need, but I now need to pop off multiple items at once into an array and I thought a list would be faster.

Zach Johnson
  • 23,678
  • 6
  • 69
  • 86
daniel
  • 43
  • 1
  • 3
  • 1
    " so i thought a list would be faster." - have you measured a performance problem? If not, you are prematurely micro-optimising... – Mitch Wheat Apr 26 '10 at 02:58
  • and premature optimization is the root of all evil (Knuth) – mmr Apr 26 '10 at 02:59
  • nope but using a queue i can only pop one off at a time, but with a list i can do a range, which in most cases is faster. – daniel Apr 26 '10 at 03:04
  • Actually, operating on a range isn't faster, unless you're adding to a `List` (because of `Capacity`) – SLaks Apr 26 '10 at 03:05
  • So your saying a simple for loops is the same speed as Array.Copy? Pretty sure Array.Copy is the fastest c# method there is to copy a group of items from one collection to another – daniel Apr 26 '10 at 03:06
  • 1
    @daniel: Perhaps, but by a _very_ small margin. (Unless the aray is very large) – SLaks Apr 26 '10 at 03:11

4 Answers4

3

Looks like Array.Reverse has native code for reversing an array which sometimes doesn't apply and would fall back to using a simple for loop. In my testing Array.Reverse is very slightly faster than a simple for loop. In this test of reversing a 1,000,000 element array 1,000 times, Array.Reverse is about 600ms whereas a for-loop is about 800ms.

I wouldn't recommend performance as a reason to use Array.Reverse though. It's a very minor difference which you'll lose the minute you load it into a List which will loop through the array again. Regardless, you shouldn't worry about performance until you've profiled your app and identified the performance bottlenecks.

    public static void Test()
    {
        var a = Enumerable.Range(0, 1000000).ToArray();

        var stopwatch = Stopwatch.StartNew();

        for(int i=0; i<1000; i++)
        {
            Array.Reverse(a);
        }

        stopwatch.Stop();

        Console.WriteLine("Elapsed Array.Reverse: " + stopwatch.ElapsedMilliseconds);

        stopwatch = Stopwatch.StartNew();

        for (int i = 0; i < 1000; i++)
        {
            MyReverse(a);
        }

        stopwatch.Stop();

        Console.WriteLine("Elapsed MyReverse: " + stopwatch.ElapsedMilliseconds);
    }

    private static void MyReverse(int[] a)
    {
        int j = a.Length - 1;
        for(int i=0; i<j; i++, j--)
        {
            int z = a[i];
            a[i] = a[j];
            a[j] = z;
        }
    }
Samuel Neff
  • 73,278
  • 17
  • 138
  • 182
  • I have identified it as a huge performance bottleneck. Currently we are pulling out one result and committing it to a database one at a time, but i'm going to make it commit a range at a time, but it needs to be in order. That is why i am doing it. – daniel Apr 26 '10 at 03:19
  • 5
    @daniel, but I assume the bottleneck is executing one query against the database at a time, not reversing the array. – Samuel Neff Apr 26 '10 at 03:22
  • true, wasn't thinking straight xD – daniel Apr 26 '10 at 03:24
1

It is not possible to do this faster than a simple for loop.

SLaks
  • 868,454
  • 176
  • 1,908
  • 1,964
0

You can accomplish it any number of ways, but the fastest way is get the elements in exactly the manner you are. You can use Array.Reverse, Array.Copy, etc., or you can use LINQ and extension methods, and both are valid alternatives, but they shouldn't be any faster.

Anthony Pegram
  • 123,721
  • 27
  • 225
  • 246
0

In one of your comments:

Currently we are pulling out one result and committing it to a database one at a time

There is a big difference between using a for loop to iterate backwards over a List<T> and committing records to a database one at a time. The former is fine; nobody's endorsing the latter.

Why not just iterate first--to populate an array--and then send that array into the database, all populated?

var myArray = new T[numItemsYouWantToSend];

int arrayIndex = 0;
for (int i = myList.Count - 1; arrayIndex < myArray.Length; --i) {
    if (i < 0) break;
    myArray[arrayIndex++] = myList[i];
}

UpdateDatabase(myArray);
Dan Tao
  • 125,917
  • 54
  • 300
  • 447