viernes, 1 de junio de 2007

Ordenamiento con IComparer<> de lista genérica

Gracias a la llegada de Generics con .NET 2.0 podemos realizar nuestro código de un modo mucho más elegante. Dentro de las clases que han obtenido beneficios de Generics nos encontramos con List<>, la cual es una lista tipada que usaremos intensamente (es muy útil) es interesante ver como se implementa el ordenamiento gracias a todo esto. List<> (y otras listas que deriban de ella) tiene un método Sort que nos permite que se ordene, vamos a ver como funciona. Lo primero que observamos es que este método tiene un par de sobrecargas, a la que vamos a prestar principal atención es a esta lista.Sort(IComparer<> comparer). ¿Qué quiere decir esto? bien, que el método necesita una clase que implemente la interfaz IComparer<> para realizar el ordenamiento (que se hace internamente con el algorítmo QuickSort), entonces observemos que define esta interfaz. (esto lo logramos gracias a Reflector, una herramienta indispensable)
public interface IComparer
{
    // Methods
    int Compare(T x, T y);
}
Un sólo método, sencillo; este método será invocado por cada elemento de la lista para saber si dicho elemento es mayor, menor o igual al siguiente, lo que nos permite esta interfaz es definir nosotros como se comparan los elementos, por ejemplo, si tenemos una lista de Usuarios nosotros le decimos que un Usuario irá delante de otro por el nombre, por la edad o lo que se nos ocurra, lo único que tenos que hacer es devolver es el método Compare(T x, T y) 1 si x > y 0 si x=y y -1 si x < y Veamos un ejemplo
using System;
using System.Collections.Generic;
using System.Text;

namespace ConsoleApplication1
{
    class Program: IComparer
    {
        static void Main(string[] args)
        {
            Program p = new Program();
            p.Test();
        }
        public void Test()
        {
            List entidades = new List();

            entidades.Add(new Entidad(2, "segunda", "nombre 2", DateTime.Now.AddHours(1)));
            entidades.Add(new Entidad(1, "primera", "nombre 1", DateTime.Now));
            entidades.Add(new Entidad(3,"Tercera","nombre 3", DateTime.Now.AddHours(2)));

            entidades.Sort(this);

        }


        #region IComparer Members

        public int Compare(Entidad x, Entidad y)
        {
            //este método se llama con cada elemento y hace que lo compare con el siguiente
            //acá poné tu criterio de comparación
            //tenés que devolver 1 si el primer elemento es mayor -1 si es menor y 0 si es igual
            if (x.Id > y.Id) return 1;
            
            if (x.Id < y.Id) return -1;

            return 0;
            
        }

        #endregion
    }
    class Entidad
    {
        private int _id;
        private string _descripcion;
        private string _nombre;
        private DateTime _fecha = new DateTime();

        public Entidad() { }
        public Entidad(int id, string descripcion, string nombre, DateTime fecha)
        {
            this.Id = id;
            this.Descripcion = descripcion;
            this.Nombre = nombre;
            this.Fecha = fecha;
        }

        public DateTime Fecha
        {
            get { return _fecha; }
            set { _fecha = value; }
        }
 

        public string Nombre
        {
            get { return _nombre; }
            set { _nombre = value; }
        }
 
        public string Descripcion
        {
            get { return _descripcion; }
            set { _descripcion = value; }
        }
 
        public int Id
        {
            get { return _id; }
            set { _id = value; }
        }
 
    }
}
Esta aplicación ordena la lista de Entidad por el id, podemos cambiar facilmente la implementación del metodo Compare(T x, T y) para que lo haga por fecha de este modo return x.Fecha.CompareTo(y.Fecha); y todas las combinaciones que nos haga falta.