代码之家  ›  专栏  ›  技术社区  ›  Eddie Deyo

在.NET 2.0中,对IList进行排序的最佳方法是什么?

  •  5
  • Eddie Deyo  · 技术社区  · 17 年前

    我有一个 IList<T> 我需要排序,如果可能的话,我宁愿不复制列表。我注意到了 ArrayList 有一个 Adapter 静态方法,包装传递的列表而不复制它,但这需要 IList 我有一个 ILIST & T;T & GT; . 从A投安全吗 System.Collections.Generic.IList<T> 到A System.Collections.IList 只需使用 适配器 方法?

    注意这是.NET 2.0,所以Linq不是一个选项。

    6 回复  |  直到 17 年前
        1
  •  13
  •   Mike C.    17 年前

    在保罗·福克斯的博客中,我推荐了“如何对一个伊利斯特人进行排序”这篇文章: http://foxsys.blogspot.com/2007/06/how-to-sort-generic-ilist.html

    为了防止博客在将来消失,我将把文章复制到这里:


    如何对通用IList排序

    更新

    你可以阅读和更新关于 sorting generic IList and List . 许多人更喜欢更新后的帖子中提到的方法。

    对通用IList排序

    我试图对一个通用的ilist进行排序,找到了一种相当简单的方法。

    步骤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

    把你的髂骨分类。为此,您将使用arraylist.adapter()方法传入IList,然后调用sort方法。像这样…

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

    注:语言类型为“ilist”

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

        2
  •  6
  •   Hallgrim    17 年前

    您不能将ilist(t)强制转换为ilist。

    在使用Reflector进行一些嗅探之后,看起来像array list.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];
    }
    

    如果列表(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];
    }
    

    如果列表太大(比如在数亿个项目中),以至于您无法在内存中创建额外的副本,我建议首先使用列表(T),或者实现您最喜欢的就地排序算法。

        3
  •  1
  •   justin.m.chase    17 年前

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

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

        4
  •  0
  •   Gord    17 年前

    我知道这不是.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

        5
  •  0
  •   Community Mohan Dere    9 年前

    如果需要对不同类的列表(而不是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(在上找到),还需要func委托 Replacing Func with delegates C# ):

    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));
        }
    }
    
        6
  •  -3
  •   sra Jon    14 年前
    IList<object> unsorted = ...
    IList<object> sortedList = unsorted.Orderby(x => x.Tostring()).Tolist();
    

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

    推荐文章