Así que hoy me encontré con un problema interesante. Tenemos un servicio web WCF que devuelve un IList. No es gran cosa hasta que quise arreglarlo.
Resulta que la interfaz IList no tiene un método de ordenación integrado.
Terminé usando el ArrayList.Adapter(list).Sort(new MyComparer())
método para resolver el problema, pero me pareció un poco "gueto".
Jugué con escribir un método de extensión, también con heredar de IList e implementar mi propio método Sort (), así como convertirlo en una Lista, pero ninguno de estos parecía demasiado elegante.
Entonces mi pregunta es, ¿alguien tiene una solución elegante para ordenar un IList
Respuestas:
¿Qué hay de usar LINQ To Objects para ordenar por usted?
Supongamos que tiene un
IList<Car>
, y el automóvil tiene unaEngine
propiedad, creo que podría ordenar de la siguiente manera:from c in list orderby c.Engine select c;
Editar: debe ser rápido para obtener respuestas aquí. Como presenté una sintaxis ligeramente diferente a las otras respuestas, dejaré mi respuesta; sin embargo, las otras respuestas presentadas son igualmente válidas.
fuente
Puede utilizar LINQ:
using System.Linq; IList<Foo> list = new List<Foo>(); IEnumerable<Foo> sortedEnum = list.OrderBy(f=>f.Bar); IList<Foo> sortedList = sortedEnum.ToList();
fuente
Esta pregunta me inspiró a escribir una publicación de blog: http://blog.velir.com/index.php/2011/02/17/ilistt-sorting-a-better-way/
Creo que, idealmente, .NET Framework incluiría un método de clasificación estático que acepta un IList <T>, pero lo mejor es crear su propio método de extensión. No es demasiado difícil crear un par de métodos que le permitan ordenar un IList <T> como lo haría con un List <T>. Como beneficio adicional, puede sobrecargar el método de extensión LINQ OrderBy utilizando la misma técnica, de modo que si está usando List.Sort, IList.Sort o IEnumerable.OrderBy, puede usar exactamente la misma sintaxis.
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)); } // Sorts in IList<T> in place, when T is IComparable<T> public static void Sort<T>(this IList<T> list) where T: IComparable<T> { Comparison<T> comparison = (l, r) => l.CompareTo(r); Sort(list, 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); } }
Con estas extensiones, ordena tu IList como lo harías con una List:
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));
Hay más información en la publicación: http://blog.velir.com/index.php/2011/02/17/ilistt-sorting-a-better-way/
fuente
ISortableList<T>
interfaz (con métodos para ordenar una parte de la lista usando algún comparador en particular),List<T>
implementarla y tener un método estático que podría ordenar cualquieraIList<T>
verificando si se implementóISortableList<T>
y, si no, copiarlo en una matriz, ordenarlo, borrarloIList<T>
y volver a agregar los elementos.IList<T> list
se puede convertir a laIList
interfaz no genérica . Si codifica su propia clase implementando laIList<T>
interfaz, asegúrese de implementar también laIList
interfaz no genérica , o el código fallará con una excepción de conversión de clase.ISortableList<T>
ofrecer que no esté ya incluidoIList<T>
? O, preguntado de otra manera, ¿por qué no seIList<T>
puede ordenar en el lugar sin volver a agregar los elementos con su método estático imaginado?IList<T>
interfaz para acceder a cada elemento. La diferencia de velocidad es lo suficientemente grande como para que, en muchos casos, sea más rápido copiar una lista en una matriz, ordenar la matriz y copiar la lista de nuevo, que intentar tener una rutina de clasificación que procese la lista en su lugar.ComparisonComparer
clase no es necesaria. En su lugar, puede utilizar el método estático estándarComparer<T>.Create(comparison)
.Creo que vas a tener que hacer algo así (convertirlo en un tipo más concreto).
Tal vez lo incluya en una Lista de T en lugar de ArrayList, de modo que obtenga seguridad de tipos y más opciones sobre cómo implementar el comparador.
fuente
La respuesta aceptada por @DavidMills es bastante buena, pero creo que se puede mejorar. Por un lado, no es necesario definir la
ComparisonComparer<T>
clase cuando el marco ya incluye un método estáticoComparer<T>.Create(Comparison<T>)
. Este método se puede utilizar para crear un archivoIComparison
sobre la marcha.Además, lanza
IList<T>
a loIList
que tiene el potencial de ser peligroso. En la mayoría de los casos que he visto,List<T>
qué implementosIList
se utilizan entre bastidores para implementarIList<T>
, pero esto no está garantizado y puede generar un código frágil.Por último, el
List<T>.Sort()
método sobrecargado tiene 4 firmas y solo 2 de ellas están implementadas.List<T>.Sort()
List<T>.Sort(Comparison<T>)
List<T>.Sort(IComparer<T>)
List<T>.Sort(Int32, Int32, IComparer<T>)
La siguiente clase implementa las 4
List<T>.Sort()
firmas para laIList<T>
interfaz: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]; } } }
Uso:
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)); }
La idea aquí es aprovechar la funcionalidad del subyacente
List<T>
para manejar la clasificación siempre que sea posible. Nuevamente, la mayoría de lasIList<T>
implementaciones que he visto usan esto. En el caso de que la colección subyacente sea de un tipo diferente, recurra a la creación de una nueva instancia deList<T>
con elementos de la lista de entrada, úsela para ordenar y luego copie los resultados a la lista de entrada. Esto funcionará incluso si la lista de entrada no implementa laIList
interfaz.fuente
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));**
fuente
Encontré este hilo mientras buscaba una solución al problema exacto descrito en la publicación original. Sin embargo, ninguna de las respuestas satisfizo mi situación por completo. La respuesta de Brody estuvo bastante cerca. Aquí está mi situación y la solución que encontré.
Tengo dos ILists del mismo tipo devueltos por NHibernate y los dos IList se han convertido en uno, de ahí la necesidad de ordenar.
Como dijo Brody, implementé un ICompare en el objeto (ReportFormat) que es el tipo de mi IList:
public class FormatCcdeSorter:IComparer<ReportFormat> { public int Compare(ReportFormat x, ReportFormat y) { return x.FormatCode.CompareTo(y.FormatCode); } }
Luego convierto el IList combinado en una matriz del mismo tipo:
ReportFormat[] myReports = new ReportFormat[reports.Count]; //reports is the merged IList
Luego ordena la matriz:
Array.Sort(myReports, new FormatCodeSorter());//sorting using custom comparer
Dado que la matriz unidimensional implementa la interfaz
System.Collections.Generic.IList<T>
, la matriz se puede utilizar como la IList original.fuente
Útil para ordenar la cuadrícula, este método clasifica la lista según los nombres de propiedad. Como sigue el ejemplo.
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(); } } }
fuente
A continuación, se muestra un ejemplo con el tipo de escritura más fuerte. Sin embargo, no estoy seguro de si es necesariamente la mejor manera.
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; } }
La función Cast es solo una reimplementación del método de extensión que viene con 3.5 escrito como un método estático normal. Desafortunadamente, es bastante feo y detallado.
fuente
En VS2008, cuando hago clic en la referencia de servicio y selecciono "Configurar referencia de servicio", hay una opción para elegir cómo el cliente deserializa las listas devueltas del servicio.
En particular, puedo elegir entre System.Array, System.Collections.ArrayList y System.Collections.Generic.List
fuente
using System.Linq; var yourList = SomeDAO.GetRandomThings(); yourList.ToList().Sort( (thing, randomThing) => thing.CompareThisProperty.CompareTo( randomThing.CompareThisProperty ) );
¡Eso es bonito! Ghetto.
fuente
Encontré una buena publicación sobre esto y pensé en compartir. Compruébalo AQUÍ
Básicamente.
Puede crear la siguiente clase y clases 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); } }
Entonces, si tiene un IList, puede ordenarlo así.
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());
Pero consulte este sitio para obtener más información ... Visítelo AQUÍ
fuente
¿Es esta una solución válida?
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();
El resultado fue: IList B A C
Lista A B C
ILista de nuevo A B C
fuente
Esto parece MUCHO MÁS SIMPLE si me preguntas. Esto funciona perfectamente para mi.
Puede usar Cast () para cambiarlo a IList y luego usar OrderBy ():
var ordered = theIList.Cast<T>().OrderBy(e => e);
DONDE T es el tipo, por ejemplo. Model.Employee o Plugin.ContactService.Shared.Contact
Entonces puedes usar un bucle for y está HECHO.
ObservableCollection<Plugin.ContactService.Shared.Contact> ContactItems= new ObservableCollection<Contact>(); foreach (var item in ordered) { ContactItems.Add(item); }
fuente
Convierta su colección
IList
enList<T>
o en alguna otra colección genérica y luego podrá consultarla / ordenarla fácilmente usando elSystem.Linq
espacio de nombres (proporcionará un montón de métodos de extensión)fuente
IList<T>
implementaIEnumerable<T>
y, por lo tanto, no es necesario convertirlo para usar operaciones de Linq.