Cuando tenemos una colección de elementos podemos utilizar los métodos de extensión OrderBy y OrderByDescending para ordenarla de forma sencilla por alguna de sus propiedades pero, ¿qué sucede cuando el criterio de ordenación es múltiple?
Para el ejemplo vamos a suponer que tenemos una variable Personas que es una lista genérica de instancias de la clase Persona. La cual tiene tres propiedades: Nombre, Apellido y Edad.
class Persona { public string Nombre { get; set; } public string Apellido { get; set; } public int Edad { get; set; } } ... List<Persona> Personas = new List<Persona>();
Class Persona Property Nombre As String Property Apellido As String Property Edad As Integer End Class .... Private Personas As New List(Of Persona)
Así podríamos ordenar de forma sencilla la lista Personas por la propiedad Apellido utilizando el método de extensión OrderBy.
IEnumerable<Persona> PersonasOrdenadas = Personas.OrderBy(p => p.Apellido);
Dim PersonasOrdenadas As IEnumerable(Of Persona) = Personas.OrderBy(Function(p) p.Nombre)
La cosa se empieza a complicar si lo que deseamos es ordenar la lista por apellido y que, los que tengan el mismo apellido, se ordenen por edad.
Podríamos utilizar otra sobrecarga del método OrderBy que recibe como parámetro un objeto que implementa la interfaz IComparer<T> que contiene la lógica para ordenar los elementos de la lista.
En primer lugar deberemos crear el comparador para la clase Persona que implementa la interfaz IComparer<Persona> y que definirá la lógica para ordenar los elementos por apellido y edad en el método Compare:
class CompareApellidoEdad : IComparer<Persona> { public int Compare(Persona x, Persona y) { int ComparaPersona = string.Compare(x.Apellido, y.Apellido); if (ComparaPersona == 0) ComparaPersona = x.Edad.CompareTo(y.Edad); return ComparaPersona; } }
Class CompareApellidoEdad Implements IComparer(Of Persona) Public Function Compare(x As Persona, y As Persona) As Integer Implements IComparer(Of Persona).Compare Dim ComparaPersona As Integer = String.Compare(x.Apellido, y.Apellido) If ComparaPersona = 0 Then ComparaPersona = x.Edad.CompareTo(y.Edad) End If Return ComparaPersona End Function End Class
Ahora ya podríamos utilizar la nueva sobrecarga del método OrderBy:
IEnumerable<Persona> PersonasOrdenadas = Personas.OrderBy(p => p, new CompareApellidoEdad());
Dim PersonasOrdenadas As IEnumerable(Of Persona) = Personas.OrderBy(Function(p) p, New CompareApellidoEdad())
Demasiado trabajo para algo tan simple ¿verdad?
Por suerte disponemos de otros dos métodos de extensión que nos permiten realizar esta tarea de una forma mucho más sencilla: ThenBy y ThenByDescending.
Estos métodos de extensión se aplican a objetos que implementan la interfaz IOrderedEnumerable, como sucede con el valor devuelto por los métodos OrderBy y OrderByDescending. Los métodos añaden el criterio de ordenación indicado respetando los existentes en el objeto IOrderedEnumerable y devuelve un nuevo objeto IOrderedEnumerable.
De esta forma resulta tremendamente sencillo realizar la ordenación:
IEnumerable<Persona> PersonasOrdenadas = Personas.OrderBy(p => p.Apellido).ThenBy(p => p.Edad);
Dim PersonasOrdenadas As IEnumerable(Of Persona) = Personas.OrderBy(Function(p) p.Apellido).ThenBy(Function(p) p.Edad)
Dado que, como ya he comentado, los métodos ThenBy y ThenByDescending devuelven también objetos del tipo IOrderedEnumerable, podemos encadenar tantos métodos ThenBy y ThenByDescending como queramos.
IEnumerable<Persona> PersonasOrdenadas = Personas.OrderBy(p => p.Apellido) .ThenBy(p => p.Edad) .ThenByDescending(p => p.Nombre);
Dim PersonasOrdenadas As IEnumerable(Of Persona) = Personas.OrderBy(Function(p) p.Apellido).ThenBy(Function(p) p.Edad).ThenByDescending(Function(p) p.Nombre)
Muy buen post Asier. Estupendo.
ResponderEliminarExcelente artículo. Me sirvió esto que no encontraba por ningún lado.
ResponderEliminarTengo enlazado un DataGridView y al pulsar cabecaras ,( DataGridView.Columns(e.ColumnIndex)), ordeno como explicas en los ejemplos:
ResponderEliminarSelect DataGridView.Columns(e.ColumnIndex).name
case "Codigo"
DataGridView.DataSource = ColDatosDeOperarios.OrderBy(Function(x) x.Codigo).ToList
case "Nombre"
DataGridView.DataSource = ColDatosDeOperarios.OrderBy(Function(x) x.Nombre).ToList
etc..
End Select
como puedo hacerlo directamente, (sin la select), sustituyendo x.Codigo, x.Nombre
Gracias y un saludo.
gracias
ResponderEliminarExcelente!!
ResponderEliminar