代码之家  ›  专栏  ›  技术社区  ›  lomaxx

在C中对IList进行排序#

  •  76
  • lomaxx  · 技术社区  · 16 年前

    所以我今天遇到了一个有趣的问题。我们有一个返回IList的WCF Web服务。在我想整理之前没什么大不了的。

    结果发现ilist接口没有内置排序方法。

    我最终使用了 ArrayList.Adapter(list).Sort(new MyComparer()) 解决这个问题的方法,但在我看来有点“贫民窟”。

    我还尝试编写一个扩展方法,从i list继承并实现我自己的sort()方法,并将其强制转换为一个列表,但这些方法都不太优雅。

    所以我的问题是,是否有人有一个优雅的解决方案来排序一个IList

    14 回复  |  直到 6 年前
        1
  •  52
  •   Brad Leach    16 年前

    如何使用Linq to对象为您排序?

    说你有一个 IList<Car> 车上有一个 Engine 属性,我相信您可以按以下方式排序:

    from c in list
    orderby c.Engine
    select c;
    

    编辑:在这里你需要快速得到答案。当我对其他答案提出稍微不同的语法时,我会留下我的答案——但是,给出的其他答案同样有效。

        2
  •  60
  •   Mark Cidade    16 年前

    您可以使用LINQ:

    using System.Linq;
    
    IList<Foo> list = new List<Foo>();
    IEnumerable<Foo> sortedEnum = list.OrderBy(f=>f.Bar);
    IList<Foo> sortedList = sortedEnum.ToList();
    
        3
  •  53
  •   David Mills    13 年前

    这个问题激励我写一篇博文: http://blog.velir.com/index.php/2011/02/17/ilistt-sorting-a-better-way/

    我认为,理想情况下,.NET框架将包含一个接受IList<t>的静态排序方法,但下一个最好的方法是创建自己的扩展方法。创建两个方法可以像创建列表一样对ilist进行排序,这并不难。另外,您可以使用相同的技术重载Linq OrderBy扩展方法,这样无论您使用的是list.sort、ilist.sort还是ienumerable.orderby,都可以使用完全相同的语法。

    public static class SortExtensions
    {
        //  Sorts an IList<T> in place.
        public static void Sort<T>(this IList<T> list, Comparison<T> comparison)
        {
            ArrayList.Adapter((IList)list).Sort(new ComparisonComparer<T>(comparison));
        }
    
        // Convenience method on IEnumerable<T> to allow passing of a
        // Comparison<T> delegate to the OrderBy method.
        public static IEnumerable<T> OrderBy<T>(this IEnumerable<T> list, Comparison<T> comparison)
        {
            return list.OrderBy(t => t, new ComparisonComparer<T>(comparison));
        }
    }
    
    // Wraps a generic Comparison<T> delegate in an IComparer to make it easy
    // to use a lambda expression for methods that take an IComparer or IComparer<T>
    public class ComparisonComparer<T> : IComparer<T>, IComparer
    {
        private readonly Comparison<T> _comparison;
    
        public ComparisonComparer(Comparison<T> comparison)
        {
            _comparison = comparison;
        }
    
        public int Compare(T x, T y)
        {
            return _comparison(x, y);
        }
    
        public int Compare(object o1, object o2)
        {
            return _comparison((T)o1, (T)o2);
        }
    }
    

    使用这些扩展,像排序列表一样对ilist进行排序:

    IList<string> iList = new []
    {
        "Carlton", "Alison", "Bob", "Eric", "David"
    };
    
    // Use the custom extensions:
    
    // Sort in-place, by string length
    iList.Sort((s1, s2) => s1.Length.CompareTo(s2.Length));
    
    // Or use OrderBy()
    IEnumerable<string> ordered = iList.OrderBy((s1, s2) => s1.Length.CompareTo(s2.Length));
    

    帖子里有更多信息: http://blog.velir.com/index.php/2011/02/17/ilistt-sorting-a-better-way/

        4
  •  9
  •   Leon Bambrick jon Z    16 年前

    你必须做我认为类似的事情(把它转换成更具体的类型)。

    也许把它放到一个t列表中,而不是数组列表中,这样就可以得到类型安全性和更多关于如何实现比较器的选项。

        5
  •  4
  •   andris    6 年前

    @davidmills的回答很好,但我认为可以改进。首先,不需要定义 ComparisonComparer<T> 当框架已包含静态方法时初始化 Comparer<T>.Create(Comparison<T>) . 此方法可用于创建 IComparison 在飞行中。

    此外,它铸造 IList<T> IList 它有潜在的危险。在我见过的大多数情况下, List<T> 实现 伊利斯特 用于在后台实现 ILIST & T;T & GT; 但这并不能保证,而且可能导致代码脆弱。

    最后,超载 List<T>.Sort() 方法有4个签名,其中只有2个被实现。

    1. 列出<t>。排序()
    2. List<T>.Sort(Comparison<T>)
    3. List<T>.Sort(IComparer<T>)
    4. List<T>.Sort(Int32, Int32, IComparer<T>)

    下面的类实现所有4个 列出<t>。排序() 的签名 ILIST & T;T & GT; 接口:

    using System;
    using System.Collections.Generic;
    
    public static class IListExtensions
    {
        public static void Sort<T>(this IList<T> list)
        {
            if (list is List<T>)
            {
                ((List<T>)list).Sort();
            }
            else
            {
                List<T> copy = new List<T>(list);
                copy.Sort();
                Copy(copy, 0, list, 0, list.Count);
            }
        }
    
        public static void Sort<T>(this IList<T> list, Comparison<T> comparison)
        {
            if (list is List<T>)
            {
                ((List<T>)list).Sort(comparison);
            }
            else
            {
                List<T> copy = new List<T>(list);
                copy.Sort(comparison);
                Copy(copy, 0, list, 0, list.Count);
            }
        }
    
        public static void Sort<T>(this IList<T> list, IComparer<T> comparer)
        {
            if (list is List<T>)
            {
                ((List<T>)list).Sort(comparer);
            }
            else
            {
                List<T> copy = new List<T>(list);
                copy.Sort(comparer);
                Copy(copy, 0, list, 0, list.Count);
            }
        }
    
        public static void Sort<T>(this IList<T> list, int index, int count,
            IComparer<T> comparer)
        {
            if (list is List<T>)
            {
                ((List<T>)list).Sort(index, count, comparer);
            }
            else
            {
                List<T> range = new List<T>(count);
                for (int i = 0; i < count; i++)
                {
                    range.Add(list[index + i]);
                }
                range.Sort(comparer);
                Copy(range, 0, list, index, count);
            }
        }
    
        private static void Copy<T>(IList<T> sourceList, int sourceIndex,
            IList<T> destinationList, int destinationIndex, int count)
        {
            for (int i = 0; i < count; i++)
            {
                destinationList[destinationIndex + i] = sourceList[sourceIndex + i];
            }
        }
    }
    

    用途:

    class Foo
    {
        public int Bar;
    
        public Foo(int bar) { this.Bar = bar; }
    }
    
    void TestSort()
    {
        IList<int> ints = new List<int>() { 1, 4, 5, 3, 2 };
        IList<Foo> foos = new List<Foo>()
        {
            new Foo(1),
            new Foo(4),
            new Foo(5),
            new Foo(3),
            new Foo(2),
        };
    
        ints.Sort();
        foos.Sort((x, y) => Comparer<int>.Default.Compare(x.Bar, y.Bar));
    }
    

    这里的想法是利用底层的功能 列表& T; 尽可能处理排序。再一次,大多数 ILIST & T;T & GT; 我看到的实现使用这个。如果基础集合是不同的类型,请回退以创建 列表& T; 对于输入列表中的元素,使用它进行排序,然后将结果复制回输入列表。即使输入列表没有实现 伊利斯特 接口。

        6
  •  2
  •   H. Pauwelyn    9 年前

    转换你的 IList 进入之内 List<T> 或者其他一些通用集合,然后您可以使用 System.Linq 命名空间(它将提供一系列扩展方法)

        7
  •  1
  •   John    14 年前

    我在寻找原始文章中描述的确切问题的解决方案时发现了这个线程。然而,没有一个答案完全符合我的情况。布罗迪的回答非常接近。这是我的情况和解决办法。

    我有两个同类型的ilist由nhibernate返回,并将这两个ilist合并为一个,因此需要进行排序。

    就像布罗迪说的,我在对象(reportformat)上实现了一个ICompare,它是我的IList类型:

     public class FormatCcdeSorter:IComparer<ReportFormat>
        {
           public int Compare(ReportFormat x, ReportFormat y)
            {
               return x.FormatCode.CompareTo(y.FormatCode);
            }
        }
    

    然后,我将合并的IList转换为相同类型的数组:

    ReportFormat[] myReports = new ReportFormat[reports.Count]; //reports is the merged IList
    

    然后对数组进行排序:

    Array.Sort(myReports, new FormatCodeSorter());//sorting using custom comparer
    

    因为一维数组实现了接口 System.Collections.Generic.IList<T> ,数组可以像原始的ilist一样使用。

        8
  •  1
  •   Bruno    14 年前

    用于网格排序此方法根据属性名对列表进行排序。如下面的例子所示。

        List<MeuTeste> temp = new List<MeuTeste>();
    
        temp.Add(new MeuTeste(2, "ramster", DateTime.Now));
        temp.Add(new MeuTeste(1, "ball", DateTime.Now));
        temp.Add(new MeuTeste(8, "gimm", DateTime.Now));
        temp.Add(new MeuTeste(3, "dies", DateTime.Now));
        temp.Add(new MeuTeste(9, "random", DateTime.Now));
        temp.Add(new MeuTeste(5, "call", DateTime.Now));
        temp.Add(new MeuTeste(6, "simple", DateTime.Now));
        temp.Add(new MeuTeste(7, "silver", DateTime.Now));
        temp.Add(new MeuTeste(4, "inn", DateTime.Now));
    
        SortList(ref temp, SortDirection.Ascending, "MyProperty");
    
        private void SortList<T>(
        ref List<T> lista
        , SortDirection sort
        , string propertyToOrder)
        {
            if (!string.IsNullOrEmpty(propertyToOrder)
            && lista != null
            && lista.Count > 0)
            {
                Type t = lista[0].GetType();
    
                if (sort == SortDirection.Ascending)
                {
                    lista = lista.OrderBy(
                        a => t.InvokeMember(
                            propertyToOrder
                            , System.Reflection.BindingFlags.GetProperty
                            , null
                            , a
                            , null
                        )
                    ).ToList();
                }
                else
                {
                    lista = lista.OrderByDescending(
                        a => t.InvokeMember(
                            propertyToOrder
                            , System.Reflection.BindingFlags.GetProperty
                            , null
                            , a
                            , null
                        )
                    ).ToList();
                }
            }
        }
    
        9
  •  1
  •   Dhanasekar Murugesan    12 年前
    try this  **USE ORDER BY** :
    
       public class Employee
        {
            public string Id { get; set; }
            public string Name { get; set; }
        }
    
     private static IList<Employee> GetItems()
            {
                List<Employee> lst = new List<Employee>();
    
                lst.Add(new Employee { Id = "1", Name = "Emp1" });
                lst.Add(new Employee { Id = "2", Name = "Emp2" });
                lst.Add(new Employee { Id = "7", Name = "Emp7" });
                lst.Add(new Employee { Id = "4", Name = "Emp4" });
                lst.Add(new Employee { Id = "5", Name = "Emp5" });
                lst.Add(new Employee { Id = "6", Name = "Emp6" });
                lst.Add(new Employee { Id = "3", Name = "Emp3" });
    
                return lst;
            }
    
    **var lst = GetItems().AsEnumerable();
    
                var orderedLst = lst.OrderBy(t => t.Id).ToList();
    
                orderedLst.ForEach(emp => Console.WriteLine("Id - {0} Name -{1}", emp.Id, emp.Name));**
    
        10
  •  0
  •   ICR    16 年前

    下面是一个使用强类型的例子。但不确定这是否是最好的方法。

    static void Main(string[] args)
    {
        IList list = new List<int>() { 1, 3, 2, 5, 4, 6, 9, 8, 7 };
        List<int> stronglyTypedList = new List<int>(Cast<int>(list));
        stronglyTypedList.Sort();
    }
    
    private static IEnumerable<T> Cast<T>(IEnumerable list)
    {
        foreach (T item in list)
        {
            yield return item;
        }
    }
    

    Cast函数只是作为普通静态方法编写的3.5附带的扩展方法的重新实现。不幸的是,它非常丑陋和冗长。

        11
  •  0
  •   Amy B    16 年前

    在VS2008中,当我单击服务引用并选择“配置服务引用”时,有一个选项可以选择客户端如何反序列化从服务返回的列表。

    值得注意的是,我可以在System.Array、System.Collections.ArrayList和System.Collections.Generic.List之间进行选择。

        12
  •  0
  •   vai    15 年前
    using System.Linq;
    
    var yourList = SomeDAO.GetRandomThings();
    yourList.ToList().Sort( (thing, randomThing) => thing.CompareThisProperty.CompareTo( randomThing.CompareThisProperty ) );
    

    太漂亮了!贫民窟

        13
  •  0
  •   Mizipzor    14 年前

    找到了一个很好的帖子,我想分享一下。 Check it out HERE

    基本上。

    可以创建以下类和IComparer类

    public class Widget {
        public string Name = string.Empty;
        public int Size = 0;
    
        public Widget(string name, int size) {
        this.Name = name;
        this.Size = size;
    }
    }
    
    public class WidgetNameSorter : IComparer<Widget> {
        public int Compare(Widget x, Widget y) {
            return x.Name.CompareTo(y.Name);
    }
    }
    
    public class WidgetSizeSorter : IComparer<Widget> {
        public int Compare(Widget x, Widget y) {
        return x.Size.CompareTo(y.Size);
    }
    }
    

    如果你有一个IList,你可以这样排序。

    List<Widget> widgets = new List<Widget>();
    widgets.Add(new Widget("Zeta", 6));
    widgets.Add(new Widget("Beta", 3));
    widgets.Add(new Widget("Alpha", 9));
    
    widgets.Sort(new WidgetNameSorter());
    widgets.Sort(new WidgetSizeSorter());
    

    但要查看更多信息,请访问此网站… 在这里看看

        14
  •  0
  •   Yoav    14 年前

    这是有效的解决方案吗?

            IList<string> ilist = new List<string>();
            ilist.Add("B");
            ilist.Add("A");
            ilist.Add("C");
    
            Console.WriteLine("IList");
            foreach (string val in ilist)
                Console.WriteLine(val);
            Console.WriteLine();
    
            List<string> list = (List<string>)ilist;
            list.Sort();
            Console.WriteLine("List");
            foreach (string val in list)
                Console.WriteLine(val);
            Console.WriteLine();
    
            list = null;
    
            Console.WriteLine("IList again");
            foreach (string val in ilist)
                Console.WriteLine(val);
            Console.WriteLine();
    

    结果是: 伊利斯特 乙 一 C

    表 一 乙 C

    再次重申 一 乙 C