How Do I Sort IList?

后端 未结 6 1263
终归单人心
终归单人心 2021-01-11 23:14

There\'s no Sort() function for IList. Can someoene help me with this? I want to sort my own IList.

Suppose this is my IList:



        
相关标签:
6条回答
  • 2021-01-11 23:40
    var sorted = myObj.OrderBy(x => x.marker);
    
    0 讨论(0)
  • 2021-01-11 23:43

    I would go against using OrderBy with a list because it's a LINQ extension method, therefore:

    • It wraps the list in an enumerable, then enumerates it and fills a new temporary list, then sorts this new list.
    • It wraps the sorted list inside another enumerable.
    • Then when you call ToList(), it iterates on it and fills another new list with the items.

    In essence: it creates and fills 2 new lists and 2 enumerables in addition to the actual sorting. In comparison, List.Sort() sorts in place and create nothing so it's way more efficient.

    My recommendation would be:

    • If you know the underlying type, use List.Sort() or Array.Sort(array)
    • If you don't know the underlying type, copy the List to a temporary array and sort it using Array.Sort(array) and return it.
    0 讨论(0)
  • 2021-01-11 23:54

    Use OrderBy

    Example

    public class MyObject() 
    {
        public int number { get; set; }
        public string marker { get; set; }
    }
    
    IList<MyObject> myobj = new List<MyObject>();
    var orderedList = myobj.OrderBy(x => x.marker).ToList();
    

    For a case insensitive you should use a IComparer

    public class CaseInsensitiveComparer : IComparer<string>
    {
        public int Compare(string x, string y)
        {
            return string.Compare(x, y, StringComparison.OrdinalIgnoreCase);
        }
    }
    
    IList<MyObject> myobj = new List<MyObject>();
    var orderedList = myobj.OrderBy(x => x.marker, new CaseInsensitiveComparer()).ToList();
    
    0 讨论(0)
  • 2021-01-11 23:54

    To sort in-place you would essentially see these two approaches:

            IList<T> list = .... // your ilist
            var sorted = list.ToArray();
            Array.Sort(sorted);
    
            for (int i = 0; i < list.Count; i++)
            {
                list[i] = sorted[i];
            }
    

    and

            IList<T> list = .... // your ilist
            ArrayList.Adapter((IList)list).Sort();
    

    The second one might look simpler but won't be great for value type collections since it incur boxing penalties. Furthermore there is no guarantee your IList<T> will be implementing IList. First one is better IMO.


    You can also use the first approach to sort an ICollection<T> in-place but it is questionable if you should expose such a functionality since ICollection<T> contract doesn't guarantee an order (think hash structures). Anyway to show you code example:

        ICollection<T> collection = .... // your icollection
        var sorted = collection.ToArray();
        Array.Sort(sorted);
    
        collection.Clear();
        foreach (var i in sorted)
        {
           collection.Add(i);
        }
    

    A note on sort stability, .NET's Array/List sorting algorithms are unstable. For a stable sort you will have to use:

            IList<T> list = .... // your ilist
            var sorted = list.OrderBy(i => i).ToArray();
    
            for (int i = 0; i < list.Count; i++)
            {
                list[i] = sorted[i];
            }
    

    This can't be as fast as unstable sorts.


    Finally, for a complete answer, perhaps a composite approach taken by watbywbarif is better:

        public static void Sort<T>(this IList<T> list, IComparer<T> comparer, bool stable)
        {
            if (stable)
            {
                list.StableSort(comparer);
            }
            else
            {
                list.UnstableSort(comparer);
            }
        }
    
        static void StableSort<T>(this IList<T> list, IComparer<T> comparer)
        {
            list.OrderBy(x => x, comparer).CopyTo(list);
        }
    
        static void UnstableSort<T>(this IList<T> list, IComparer<T> comparer)
        {
            switch (list)
            {
                case List<T> l:
                    l.Sort(comparer);
                    break;
    
                case T[] a:
                    Array.Sort(a, comparer);
                    break;
    
                default:
                    T[] sortable = list.ToArray();
                    sortable.UnstableSort(comparer);
                    sortable.CopyTo(list);
                    break;
            }
        }
    
        static void CopyTo<T>(this IEnumerable<T> source, IList<T> target)
        {
            int i = 0;
            foreach (T item in source)
            {
                target[i++] = item;
            }
        }
    

    That's as far as built-in approaches go. For faster implemenation you will have to roll out your own, see: https://stackoverflow.com/a/19167475

    0 讨论(0)
  • 2021-01-11 23:56

    For explanation why not to use OrderBy or similar check Christophe's answer.

    Here is one attempt to make fast Sort:

    public static void Sort<T>(this IList<T> ilist)
    {
        switch(ilist)
        {
            case List<T> lst:
                lst.Sort();
                break;
            case Array arr:
                Array.Sort(arr);
                break;
            default:
                throw new NotImplementedException();
                // or add slow impl if you don't want this to fail!!
        }
    }
    
    0 讨论(0)
  • 2021-01-12 00:02

    OrderBy definitely gets the job done, but I personally prefer the syntax of List.Sort because you can feed it a Comparison<T> delegate instead of having to write a class that implements IComparer<T>. We can accomplish that goal with an extension method, and if that's something you're interested in, check out SortExtensions:

    http://blog.velir.com/index.php/2011/02/17/ilistt-sorting-a-better-way/

    0 讨论(0)
提交回复
热议问题