如何在IList上使用Reverse(Array,Int32,Int32)或List <t> :: Reverse Method(Int32,Int32)?</t>

时间:2012-07-02 13:57:44

标签: c#

我的计划密集使用Reverse,例如Array.Reverse(myArray,3,5)

我希望我的程序可以接受arrayList作为输入,所以我选择IList

但是,我找不到与IList相同的Reverse方法。

有一个名为Reverse的扩展方法,但它会生成IEnumerable流但不会进行就地重新排列。 (我假设需要更多的复制时间)

我想过使用cast,但担心cast也会效率低下。

那么,我该怎么办?

最糟糕的情况是,我制作2个程序,1个接受数组,另一个接受List,然后重载?

5 个答案:

答案 0 :(得分:1)

OOP-way - 制作一个包装器,重载十几次:

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);
}

每当你需要以这种方式反转另一个类似于集合的类时,添加一个重载。这种方法依赖于系统内部,非常有效和强大,但如果您愿意撤销多种对象,可能会很冗长。

我灿做它自己,更好的方式:

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++;
        }
    }
}

只需添加范围检查/前置条件/​​不变量/等。此外,列表可能效率低下,因为它需要随机访问列表的内容,但我认为你不能使用“常规武器”解决它(即不使用反射和直接内存操作)。

所以,我的建议 - 超载是要走的路。

答案 1 :(得分:1)

Linq Reverse()扩展方法错过了一个明显的优化,总是创建一个临时数组来存储元素以反转它们。这在列表或数组上使用太贵了。

如果你想要就地反转那么你可以编写一个扩展方法来选择正确的Reverse()方法:

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();
    }
}

你可以用同样的方法修复Linq Reverse方法:

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;
            }
        }
    }
}

答案 2 :(得分:0)

Reverse()将直接根据列表生成IEnumerable;不涉及复制。尝试一下,如果你只是迭代它可能会更有效。

答案 3 :(得分:0)

Array.Reverse()是静态的:

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

List.Reverse不是:

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

还有一个LINQ扩展方法:

IList<T> ilist = ...
IEnumerable<T> e = ilist.AsEnumerable();
IEnumerable<T> result = e.Reverse(); // not in-place

答案 4 :(得分:0)

如果你想要一个采用IList的就地反向方法,而不仅仅是一个List或一个数组,你必须自己编写它。这不是一个特别复杂的算法,所以我想你自己能够编写这样的方法。