在.Net 2.0中对IList <t>进行排序的最佳方法是什么?</t>

时间:2008-10-22 18:23:42

标签: .net .net-2.0

我需要排序IList<T>,如果可能,我宁愿不复制列表。我注意到ArrayList有一个Adapter静态方法,它包装传递的列表而不复制它,但这需要IList,我有一个IList<T>。从System.Collections.Generic.IList<T>转换为System.Collections.IList并使用Adapter方法是否安全?

请注意,这是.Net 2.0,因此LINQ不是一个选项。

6 个答案:

答案 0 :(得分:13)

在Paul Fox的博客中,我推荐帖子“如何排序IList”:http://foxsys.blogspot.com/2007/06/how-to-sort-generic-ilist.html

如果博客将来消失,我会在这里复制帖子:


如何对通用IList进行排序

更新

您可以阅读并更新有关sorting generic IList and List的帖子。很多人会更喜欢更新帖子中提到的方法。

对通用IList进行排序

我试图对通用IList&lt;&gt;进行排序并找到了一种相当简单的方法。

第1步

您需要为IList中包含的类型实现IComparable。对于这个例子,我将使用一个简单的语言Dto类。

public class LanguageDto : IComparable {
 private String name;
 public string Name { get { return name; } set { name = value; } }

 public LanguageDto(string name) {
     this.name = name;
 }

 #region IComparable Members
 public int CompareTo(object obj) {
     if (obj is LanguageDto) {
     LanguageDto language = (LanguageDto)obj;
     return this.name.CompareTo(language.name);
     }
     throw new ArgumentException(string.Format("Cannot compare a LanguageDto to an {0}", obj.GetType().ToString()));
 }
 #endregion
}

第2步

对您的IList进行排序。为此,您将使用传入IList的ArrayList.Adapter()方法,然后调用Sort方法。像这样......

ArrayList.Adapter((IList)languages).Sort();

注意:语言的类型为“IList”

语言应该是您的类型的排序列表!

答案 1 :(得分:6)

您无法将IList(T)强制转换为IList。

在使用Reflector进行一些嗅探之后,看起来像ArrayList.Adapter(IList).Sort()将首先将列表复制到对象数组,对数组进行排序,然后将数组复制回列表:

object[] array = new object[count];
this.CopyTo(index, array, 0, count);
Array.Sort(array, 0, count, comparer);
for (int i = 0; i < count; i++)
{
    this._list[i + index] = array[i];
}

如果List(T)中的T为值类型,则可能会导致拳击开销。

如果您需要更改列表中对象的顺序,可以这样做:

IList<object> unsorted = ...
List<object> sorted = new List<object>(unsorted);
sorted.Sort(); 
for (int i = 0; i < unsorted.Countt; i++)
{
    unsorted[i] = sorted[i];
}

如果列表如此庞大(如数以亿计的项目),你无法在内存中制作额外的副本,我建议首先使用List(T)或实现你最喜欢的就地排序算法。< / p>

答案 2 :(得分:1)

由于Sort方法不在IList接口上,您可以考虑创建自己的:

interface ISortableList<T> : IList<T>
{
    void Sort();
    void Sort(IComparer<T> comparer);
}

class SortableList<T> : List<T>, ISortableList<T> { }

/* usage */
void Example(ISortedList<T> list)
{
    list.Sort();
    list.Sort(new MyCustomerComparer());
}

通常,您在方法中指定的参数类型应该是您实际需要调用的成员的最小公分母。如果您确实需要调用Sort()方法,那么您的参数应该定义该成员。否则你应该将它加载到另一个可以做你想要的对象,例如:

void Example(IList<T> list)
{
    list = new List<T>(list).Sort();
}

这实际上应该非常快,几乎肯定比编写自己的自定义内联排序算法更快。

答案 3 :(得分:0)

我知道它不是.NET 2.0,但我非常喜欢LINQ,并且每次机会都会认可它。)

简单排序:

var sortedProducts =
    from p in products
    orderby p.ProductName
    select p;

ObjectDumper.Write(sortedProducts);

按多个条件排序:

string[] digits = { "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine" };

var sortedDigits =
    from d in digits 
    orderby d.Length, d
    select d;

这两个例子都来自101 Linq Samples

答案 4 :(得分:0)

如果你需要对不同类的列表(而不是IList)进行排序而不需要为它们创建一个单独的比较器类,并且仍然保持你的实体类干净(你不想实现IComparable),你可以使用以下(与.NET 2.0兼容):

public class DynamicComparer<T> : IComparer<T>
{

    private Func<T, int> calculateFunc;
    private int calculateMultiplier;

    private Func<T, T, int> compareFunc;
    public DynamicComparer(Func<T, int> calculateFunc, bool reverse = false)
    {
        if (calculateFunc == null)
        {
            throw new Exception("Delegate function 'calculateFunc' cannot be null.");
        }

        this.calculateFunc = calculateFunc;
        this.calculateMultiplier = reverse ? -1 : 1;
        this.compareFunc = null;
    }

    public DynamicComparer(Func<T, T, int> compareFunc)
    {
        if (calculateFunc == null)
        {
            throw new Exception("Delegate function 'compareFunc' cannot be null.");
        }

        this.calculateFunc = null;
        this.compareFunc = compareFunc;
    }

    public int Compare(T x, T y)
    {
        if (calculateFunc != null)
        {
            return (calculateFunc(x) - calculateFunc(y)) * this.calculateMultiplier;
        }
        if (compareFunc != null)
        {
            return compareFunc(x, y);
        }

        throw new Exception("Compare not possible because neither a Compare or a Calculate function was specified.");
    }
}

如果您使用的是.NET 2.0(在Replacing Func with delegates C#上找到),您还需要Func代理:

public delegate TResult Func<T, TResult>(T t);
public delegate TResult Func<T, U, TResult>(T t, U u);

用法:

myList.Sort(new DynamicComparer<MyClass>(x => x.MyIntProperty) // Ascending
myList.Sort(new DynamicComparer<MyClass>(x => x.MyIntProperty, true) // Descending

一些简单的单元测试:

[TestClass()]
public class DynamicComparerTU
{
    [TestMethod()]
    public void SortIntList()
    {
        // Arrange
        dynamic myIntArray = new int[] {
            4,
            1,
            9,
            0,
            4,
            7
        };
        dynamic myIntList = new List<int>(myIntArray);

        // Act
        int temp = 0;
        for (int write = 0; write <= myIntArray.Length - 1; write++)
        {
            for (int sort = 0; sort <= myIntArray.Length - 2; sort++)
            {
                if (myIntArray(sort) > myIntArray(sort + 1))
                {
                    temp = myIntArray(sort + 1);
                    myIntArray(sort + 1) = myIntArray(sort);
                    myIntArray(sort) = temp;
                }
            }
        }

        myIntList.Sort(new DynamicComparer<int>(x => x));

        // Assert
        Assert.IsNotNull(myIntList);
        Assert.AreEqual(myIntArray.Length, myIntList.Count);
        for (int i = 0; i <= myIntArray.Length - 1; i++)
        {
            Assert.AreEqual(myIntArray(i), myIntList(i));
        }
    }

    [TestMethod()]
    public void SortStringListByLength()
    {
        // Arrange
        dynamic myStringArray = new string[] {
            "abcd",
            "ab",
            "abcde",
            "a",
            "abc"
        };
        dynamic myStringList = new List<string>(myStringArray);

        // Act
        myStringList.Sort(new DynamicComparer<string>(x => x.Length));

        // Assert
        Assert.IsNotNull(myStringList);
        Assert.AreEqual(5, myStringList.Count);
        Assert.AreEqual("a", myStringList(0));
        Assert.AreEqual("ab", myStringList(1));
        Assert.AreEqual("abc", myStringList(2));
        Assert.AreEqual("abcd", myStringList(3));
        Assert.AreEqual("abcde", myStringList(4));
    }

    [TestMethod()]
    public void SortStringListByLengthDescending()
    {
        // Arrange
        dynamic myStringArray = new string[] {
            "abcd",
            "ab",
            "abcde",
            "a",
            "abc"
        };
        dynamic myStringList = new List<string>(myStringArray);

        // Act
        myStringList.Sort(new DynamicComparer<string>(x => x.Length, true));

        // Assert
        Assert.IsNotNull(myStringList);
        Assert.AreEqual(5, myStringList.Count);
        Assert.AreEqual("abcde", myStringList(0));
        Assert.AreEqual("abcd", myStringList(1));
        Assert.AreEqual("abc", myStringList(2));
        Assert.AreEqual("ab", myStringList(3));
        Assert.AreEqual("a", myStringList(4));
    }
}

答案 5 :(得分:-3)

IList<object> unsorted = ...
IList<object> sortedList = unsorted.Orderby(x => x.Tostring()).Tolist();

这将在对象的特定字段上给出排序列表。