在C#中对IList进行sorting
所以我今天遇到了一个有趣的问题。 我们有一个WCF Web服务返回一个IList。 没有什么大不了的,直到我想分类。
原来IList接口没有内置的sorting方法。
我结束了使用ArrayList.Adapter(list).Sort(new MyComparer())
方法来解决这个问题,但它似乎有点“贫民窟”给我。
我玩弄了一个扩展方法,也从IListinheritance和实现我自己的Sort()方法以及铸造到一个列表,但没有一个看起来过于优雅。
所以我的问题是,有没有人有一个优雅的解决scheme来sortingIList
如何使用LINQ到对象为你sorting?
假设你有一个IList<Car>
,并且该车有一个Engine
属性,我相信你可以按如下方式sorting:
from c in list orderby c.Engine select c;
编辑:你需要迅速得到答案在这里。 由于我提出了与其他答案略有不同的语法,我会留下我的答案 – 但是,其他答案同样有效。
你可以使用LINQ:
using System.Linq; IList<Foo> list = new List<Foo>(); IEnumerable<Foo> sortedEnum = list.OrderBy(f=>f.Bar); IList<Foo> sortedList = sortedEnum.ToList();
这个问题激发了我写博客文章: http : //blog.velir.com/index.php/2011/02/17/ilistt-sorting-a-better-way/
我认为,理想情况下,.NET Framework将包含一个接受IList <T>的静态sorting方法,但是下一个最好的方法是创build自己的扩展方法。 创build一些方法可以让你像列表<T>那样排列一个IList <T>并不难。 作为奖励,您可以使用相同的技术重载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进行sorting:
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));
post中有更多信息: http : //blog.velir.com/index.php/2011/02/17/ilistt-sorting-a-better-way/
你将不得不做这样的事情,我认为(把它转换成更具体的types)。
也许把它放到一个T列表而不是ArrayList中,这样你就可以获得types安全性和更多选项来实现比较器。
@DavidMills接受的答案是相当不错的,但我认为可以改进。 首先,当框架已经包含一个静态方法Comparer<T>.Create(Comparison<T>)
时,不需要定义ComparisonComparer<T>
类。 这个方法可以用来创build一个即时比较。
另外,它把IList<T>
投给了IList
,这有潜在危险。 在我看到的大多数情况下,实现IList
List<T>
在后台用于实现IList<T>
,但这不能保证,并且会导致代码变得脆弱。
最后,重载的List<T>.Sort()
方法有4个签名,只有2个被实现。
-
List<T>.Sort()
-
List<T>.Sort(Comparison<T>)
-
List<T>.Sort(IComparer<T>)
-
List<T>.Sort(Int32, Int32, IComparer<T>)
下面的类实现IList<T>
接口的所有4个List<T>.Sort()
签名:
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(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)); }
这里的想法是利用底层List<T>
来尽可能地处理sorting。 再一次,我见过的大多数IList<T>
实现都使用这个。 在底层集合是不同types的情况下,回退到使用input列表中的元素创buildList<T>
的新实例,使用它来执行sorting,然后将结果复制回input列表。 即使input列表没有实现IList
接口,这也可以工作。
将您的IList
转换为List<T>
或其他generics集合,然后使用System.Linq
命名空间轻松查询/sorting(它将提供一堆扩展方法)
find这个线程,当我正在寻找一个解决scheme的原始文章中描述的确切问题。 但是,没有一个答案完全符合我的情况。 布罗迪的回答非常接近。 这是我发现的情况和解决scheme。
我有两个由NHibernate返回的相同types的IList,并将两个IList合并为一个,因此需要sorting。
就像Brody说的,我在对象(ReportFormat)上实现了一个ICompare,这是我的IList的types:
public class FormatCcdeSorter:IComparer<ReportFormat> { public int Compare(ReportFormat x, ReportFormat y) { return x.FormatCode.CompareTo(y.FormatCode); } }
然后我将合并的IList转换为相同types的数组:
ReportFormat[] myReports = new ReportFormat[reports.Count]; //reports is the merged IList
然后对数组进行sorting:
Array.Sort(myReports, new FormatCodeSorter());//sorting using custom comparer
由于一维数组实现了System.Collections.Generic.IList<T>
接口,因此可以像使用原始IList一样使用该数组。
对于网格sorting很有用,这个方法根据属性名称对列表进行sorting。 如下例所示。
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(); } } }
以下是使用较强types的示例。 不知道这是否是最好的方式。
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作为普通静态方法编写的扩展方法的重新实现。 不幸的是这是相当丑陋和冗长的。
在VS2008中,当我点击服务引用并select“configuration服务引用”时,有一个选项可以select客户端如何反序列化从服务返回的列表。
值得注意的是,我可以selectSystem.Array,System.Collections.ArrayList和System.Collections.Generic.List
using System.Linq; var yourList = SomeDAO.GetRandomThings(); yourList.ToList().Sort( (thing, randomThing) => thing.CompareThisProperty.CompareTo( randomThing.CompareThisProperty ) );
这很漂亮!贫民窟。
find一个好的post,并认为我会分享。 看看这里
基本上。
您可以创build以下类和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,你可以像这样sorting。
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());
但检查这个网站的更多信息… 看看这里
这是一个有效的解决scheme?
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();
结果是:IList B A C
列表A B C
IList再次A B C
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));**