2

My program intensively uses Reverse, e.g. Array.Reverse(myArray,3,5)

I would like my program could accept both array and List as input, so I go for IList

However, I couldn't find an IList method which is the same as Reverse.

There is one extension method named Reverse, however it produces IEnumerable stream but not in-place rearrangement. (which I assume takes more copy time)

I thought of using cast, but was afraid that cast would be inefficient as well.

So, what should I do?

Worst case scenario, I make 2 program, 1 takes array, the other takes List, and then overloading?

colinfang
  • 20,909
  • 19
  • 90
  • 173
  • This might help you with your `IList` problems. http://stackoverflow.com/questions/4673136/why-does-ilist-reverse-not-work-like-list-reverse – code4life Jul 02 '12 at 13:59
  • Maybe it's a good idea to give up using concrete classes like Array and List and go for their interfaces? Maybe IEnumerable is suitable for your needs? All in all, you can always get back your list or array from the IEnumerable. – J0HN Jul 02 '12 at 14:06
  • @J0HN No, you can't get back the `List` or `Array` when using an `IEnumerable`. You can make a new list or a new array, but that's quite different – Servy Jul 02 '12 at 14:25
  • @Servy I never mean't it would be exactly the same array. Yes, it would definitely build new array, but still, aren't avoiding this array reconstruction is a premature optimization? Only OP knows :) – J0HN Jul 02 '12 at 14:30
  • @J0HN When you say get back "your array" rather than "an array" it does imply the same one, yes. Additionally, the OP *does* state that it's important to do the reverse in place. This is partly due to the fact that he's referencing the Reverse overload that takes two `int` parameters that allow reversing only a portion of the array rather than the whole thing. There can also be reasons other than optimization to want to do it in-place (because it's important to affect other references to the object that you may not control). – Servy Jul 02 '12 at 14:39

5 Answers5

1

OOP-way - make a wrapper, overload it dozen times:

public void Reverse(Array arr, int index, int count)
{
    Array.Reverse(arr, index, count);
}
public void Reverse<T>(List<T> lst, int index, int count)
{
    lst.Reverse(index, count);
}

Add an overload each time you need another collection-alike class to be reversed in such way. This approach relies on system internals, very effective and robust, but may be verbose in case you are willing to reverse many kinds of objects.

I-can-do-it-myself-better-way:

static class Extensions
{
    public static void Reverse(this IList target, int index, int count)
    {
        int right = index + count - 1;
        int left = index;
        while (right>left)
        {
            var tmp = target[left];
            target[left] = target[right];
            target[right] = tmp;
            right--;
            left++;
        }
    }
}

Just add range checks/preconditions/invariants/etc. Also, it might be inefficient with lists, as it requires random access to the contents of the list, but I think you can't workaround it using "conventional weapons" (i.e. not using reflection and direct memory manipulation).

So, my suggestion - overloading is the way to go.

J0HN
  • 26,063
  • 5
  • 54
  • 85
1

The Linq Reverse() extension method misses an obvious optimization, it always creates a temporary array to store elements to reverse them. This is too expensive to use on a list or array.

If you want an in-place reverse then you could write an extension method that selects the proper Reverse() method:

public static class MyExtensions {
    public static void Reverse<T>(this IList<T> source) {
        if (source is List<T>) {
            ((List<T>)source).Reverse();
        }
        else if (source is T[]) {
            Array.Reverse((T[])source);
        }
        else throw new ArgumentException();
    }
}

You can fix the Linq Reverse method the same way:

public static class MyExtensions {
    public static IEnumerable<T> Reverse<T>(this IEnumerable<T> source) {
        if (source is IList<T>) {
            var list = (IList<T>)source;
            for (int ix = list.Count - 1; ix >= 0; --ix) {
                yield return list[ix];
            }
        }
        else {
            foreach (var item in Enumerable.Reverse(source)) {
                yield return item;
            }
        }
    }
}
Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
0

Reverse() will produce an IEnumerable directly based off the list; no copying involved. Give it a try, it may be more efficient if you're only iterating.

Ry-
  • 218,210
  • 55
  • 464
  • 476
0

Array.Reverse() is static:

T[] arr = ...
Array.Reverse(arr); // in-place

List.Reverse is not :

List<T> list = ...
list.Reverse(); // in-place too

Also there is a LINQ extension method:

IList<T> ilist = ...
IEnumerable<T> e = ilist.AsEnumerable();
IEnumerable<T> result = e.Reverse(); // not in-place
abatishchev
  • 98,240
  • 88
  • 296
  • 433
0

If you want an in-place Reverse method that takes an IList, rather than just a List or an Array, you'll have to write it yourself. It's not a particularly complex algorithm, so I imagine you're capable of writing such a method yourself.

Servy
  • 202,030
  • 26
  • 332
  • 449