Ordenar un List o IList

16/01/2007 - 18:31 por ANT1 | Informe spam
Como se hace para ordenar una lista List<> o IList<> generica de una
clase propia con sus propiedades internas (sus strings, ints, doubles,
...).

He estado mirando las interfaces Icomparable e Icomparer pero soy
incapaz de comprenderlas.

¿Alguien puede echarme un cable?

Preguntas similare

Leer las respuestas

#1 Alberto Poblacion
16/01/2007 - 18:50 | Informe spam
"ANT1" wrote in message
news:
Como se hace para ordenar una lista List<> o IList<> generica de una
clase propia con sus propiedades internas (sus strings, ints, doubles,
...).

He estado mirando las interfaces Icomparable e Icomparer pero soy
incapaz de comprenderlas.



Hay dos formas de hacerlo: Llamando a MiLista.Sort(), o a
MiLista.Sort(comparador). En el primer caso, los objetos de la lista se
ordenan llamando al comparador de la clase de los objetos, y en el segundo
se escribe por separado una clase comparadora, se crea una instancia de
ella, y se le pasa como argumento al Sort. Quizá sea un poco más simple de
entender el primer caso:

Supongamos que tienes un lista List<Empleado>, donde tu clase empleado
tiene dentro datos como Nombre, DNI, etc. ¿Qué se entiende por ordenarla? Se
trata de poner los empleados en un cierto orden, de menor a mayor, para lo
cual hay que definir qué significa que "un empleado es mayor que otro". Por
ejemplo, si quisiéramos ordenarlos por orden alfabético de Nombre, entonces
entenderíamos que es mayor el que tenga un nombre que quede más adelante en
el alfabeto. Esto es precisamente lo que tiene que decirnos la función
Compare que meteremos dentro de la clase Empleado, que debe devolver -1, 0 o
1 en función del resultado de la comparación.

Aqui va un ejemplo en el que usamos un comparador de tipo Generic
(también se puede usar uno tradicional con argumentos de tipo Object):

public class Empleado: IComparable<Empleado>
{
public string Nombre;
...
public int CompareTo(Empleado elOtro)
{
return this.Nombre.CompareTo(elOtro.Nombre);
}
}

...

List<Emplado> lista = new List<Empleado>;
lista.Add(new Empleado(...));
lista.Add(new Empleado(...));
lista.Add(new Empleado(...));
lista.Sort();
Respuesta Responder a este mensaje
#2 ANT1
17/01/2007 - 09:38 | Informe spam
Precisamente estaba yo a punto de probar el segundo metodo que me
comentas. El de "comparion". Aun no lo habia hecho pq no tengo los
suficientes objetos para realizar unas pruebas adecuadas pero en ello
me ponia ahora.

La explicacion que me has dado la verdad es que me vienemuy bien porqur
habia una serie de cosas que no comprendia del Icomparable, y creeme
que las voy a probar.

Pero fijandome a mi entender no son tan diferentes un metodo que otro.
Yo cuando he tratado de meterme con el Icomparer y el IComparable era
porque pensaba que de esta forma, teniendo una clase con multiples
propiedades, podria ordenarla facilemente por la propiedad que
quisiese, es decir y con el ejemplo que tu has dado, algo asi:

Empleado.Sort("Nombre");

Sin necesidad de implementar un metodo de comparación para cada
propiedad. Y es que pensaba que habria alguna menra de hacerlo al ser
estas propiedades strings, ints, doubles, etc... que ya tienen sus
propios metodos de comparacion.

¿Esto no se puede hacer? Tendria que haber algun metodo digo yo.

Ahora mismo se me ocurre... vi el otro dia que alguien ponia como
generar un objeto de una clase que ya se tenia definida a partr de un
string que se pasaba dinamicamente. Algo asi:

string clase = "Una Clase Mia";

clase Nuevo Objeto = new clase();

Todo esto si no recuerdo mal.

Si se pudiese enviar un parametro string con el tipo de clase al
Comparision, entonces en este solo habria que hacer algo asi:

public static int Compara(object X, object Y, string clase) // Si
se pudiese hacer q no lo se
{
clase ObjetoX = (clase)X;
clase ObjetoY = (clase)Y;
return ObjetoX.CompareTo(ObjetoY);
//Aunque aqui veo que no sabria que clase es ni si tiene el metodo
CompareTo(); Esto no valdria de primeras
}

Ademas de es habria que añadir las comparaciones si son null y tal,
pero creo que sirve para ver por donde quiero tirar yo.

La verdad que lo que he puesto ahi es lo que se me ha ocurrido ahora
mismo y tiene una pinta de fallar por todos lados, ya que no se si
realmente se podria pasar el parametro "clase", que lo dudo mucho, y ya
que al ser una clase desconocida (puede ser cualquiera) no sabria si
tene el CompareTo() y no nos dejaria utilizarlo.

Pero bueno. Creo que sirve de ejemplo para mis ideas. ¿Se puede hacer
algo parecido?


Alberto Poblacion ha escrito:

"ANT1" wrote in message
news:
> Como se hace para ordenar una lista List<> o IList<> generica de una
> clase propia con sus propiedades internas (sus strings, ints, doubles,
> ...).
>
> He estado mirando las interfaces Icomparable e Icomparer pero soy
> incapaz de comprenderlas.

Hay dos formas de hacerlo: Llamando a MiLista.Sort(), o a
MiLista.Sort(comparador). En el primer caso, los objetos de la lista se
ordenan llamando al comparador de la clase de los objetos, y en el segundo
se escribe por separado una clase comparadora, se crea una instancia de
ella, y se le pasa como argumento al Sort. Quizá sea un poco más simple de
entender el primer caso:

Supongamos que tienes un lista List<Empleado>, donde tu clase empleado
tiene dentro datos como Nombre, DNI, etc. ¿Qué se entiende por ordenarla? Se
trata de poner los empleados en un cierto orden, de menor a mayor, para lo
cual hay que definir qué significa que "un empleado es mayor que otro". Por
ejemplo, si quisiéramos ordenarlos por orden alfabético de Nombre, entonces
entenderíamos que es mayor el que tenga un nombre que quede más adelante en
el alfabeto. Esto es precisamente lo que tiene que decirnos la función
Compare que meteremos dentro de la clase Empleado, que debe devolver -1, 0 o
1 en función del resultado de la comparación.

Aqui va un ejemplo en el que usamos un comparador de tipo Generic
(también se puede usar uno tradicional con argumentos de tipo Object):

public class Empleado: IComparable<Empleado>
{
public string Nombre;
...
public int CompareTo(Empleado elOtro)
{
return this.Nombre.CompareTo(elOtro.Nombre);
}
}

...

List<Emplado> lista = new List<Empleado>;
lista.Add(new Empleado(...));
lista.Add(new Empleado(...));
lista.Add(new Empleado(...));
lista.Sort();
Respuesta Responder a este mensaje
#3 ANT1
17/01/2007 - 09:47 | Informe spam
Encontre el ejemplo que decia, creo, y resulta que es tuyo Alberto.

public void CrearForm(Type miFormularioTipo)
{
Form f = (Form)Activator.CreateInstance(miFormularioTipo);
f.Show()
}

pero era para crear un formulario mediante el Type.

Esto desequilibra mas mis teorias. Mirare la clase Type a ver que me
dice.



On 17 ene, 09:38, "ANT1" wrote:
Precisamente estaba yo a punto de probar el segundo metodo que me
comentas. El de "comparion". Aun no lo habia hecho pq no tengo los
suficientes objetos para realizar unas pruebas adecuadas pero en ello
me ponia ahora.

La explicacion que me has dado la verdad es que me vienemuy bien porqur
habia una serie de cosas que no comprendia del Icomparable, y creeme
que las voy a probar.

Pero fijandome a mi entender no son tan diferentes un metodo que otro.
Yo cuando he tratado de meterme con el Icomparer y el IComparable era
porque pensaba que de esta forma, teniendo una clase con multiples
propiedades, podria ordenarla facilemente por la propiedad que
quisiese, es decir y con el ejemplo que tu has dado, algo asi:

Empleado.Sort("Nombre");

Sin necesidad de implementar un metodo de comparación para cada
propiedad. Y es que pensaba que habria alguna menra de hacerlo al ser
estas propiedades strings, ints, doubles, etc... que ya tienen sus
propios metodos de comparacion.

¿Esto no se puede hacer? Tendria que haber algun metodo digo yo.

Ahora mismo se me ocurre... vi el otro dia que alguien ponia como
generar un objeto de una clase que ya se tenia definida a partr de un
string que se pasaba dinamicamente. Algo asi:

string clase = "Una Clase Mia";

clase Nuevo Objeto = new clase();

Todo esto si no recuerdo mal.

Si se pudiese enviar un parametro string con el tipo de clase al
Comparision, entonces en este solo habria que hacer algo asi:

public static int Compara(object X, object Y, string clase) // Si
se pudiese hacer q no lo se
{
clase ObjetoX = (clase)X;
clase ObjetoY = (clase)Y;
return ObjetoX.CompareTo(ObjetoY);
//Aunque aqui veo que no sabria que clase es ni si tiene el metodo
CompareTo(); Esto no valdria de primeras

}Ademas de es habria que añadir las comparaciones si son null y tal,
pero creo que sirve para ver por donde quiero tirar yo.

La verdad que lo que he puesto ahi es lo que se me ha ocurrido ahora
mismo y tiene una pinta de fallar por todos lados, ya que no se si
realmente se podria pasar el parametro "clase", que lo dudo mucho, y ya
que al ser una clase desconocida (puede ser cualquiera) no sabria si
tene el CompareTo() y no nos dejaria utilizarlo.

Pero bueno. Creo que sirve de ejemplo para mis ideas. ¿Se puede hacer
algo parecido?

Alberto Poblacion ha escrito:

> "ANT1" wrote in message
>news:
> > Como se hace para ordenar una lista List<> o IList<> generica de una
> > clase propia con sus propiedades internas (sus strings, ints, doubles,
> > ...).

> > He estado mirando las interfaces Icomparable e Icomparer pero soy
> > incapaz de comprenderlas.

> Hay dos formas de hacerlo: Llamando a MiLista.Sort(), o a
> MiLista.Sort(comparador). En el primer caso, los objetos de la lista se
> ordenan llamando al comparador de la clase de los objetos, y en el segundo
> se escribe por separado una clase comparadora, se crea una instancia de
> ella, y se le pasa como argumento al Sort. Quizá sea un poco más simple de
> entender el primer caso:

> Supongamos que tienes un lista List<Empleado>, donde tu clase empleado
> tiene dentro datos como Nombre, DNI, etc. ¿Qué se entiende por ordenarla? Se
> trata de poner los empleados en un cierto orden, de menor a mayor, para lo
> cual hay que definir qué significa que "un empleado es mayor que otro". Por
> ejemplo, si quisiéramos ordenarlos por orden alfabético de Nombre, entonces
> entenderíamos que es mayor el que tenga un nombre que quede más adelante en
> el alfabeto. Esto es precisamente lo que tiene que decirnos la función
> Compare que meteremos dentro de la clase Empleado, que debe devolver -1, 0 o
> 1 en función del resultado de la comparación.

> Aqui va un ejemplo en el que usamos un comparador de tipo Generic
> (también se puede usar uno tradicional con argumentos de tipo Object):

> public class Empleado: IComparable<Empleado>
> {
> public string Nombre;
> ...
> public int CompareTo(Empleado elOtro)
> {
> return this.Nombre.CompareTo(elOtro.Nombre);
> }
> }

> ...

> List<Emplado> lista = new List<Empleado>;
> lista.Add(new Empleado(...));
> lista.Add(new Empleado(...));
> lista.Add(new Empleado(...));
> lista.Sort();
Respuesta Responder a este mensaje
#4 Alberto Poblacion
17/01/2007 - 10:07 | Informe spam
"ANT1" wrote in message
news:
[...]
Empleado.Sort("Nombre");



La forma de hacer esto es esta:

Empleado.Sort(new MiClaseComparadora<Tipo>("Nombre"));

En el constructor de MiClaseComparadora recibes el argumento "Nombre",
lo guardas en una variable privada de la clase, y ya sabes cuál es el campo
que hay que comparar. En <Tipo> le pasas la clase cuyos objetos hay que
comparar, con lo que consigues que el acceso a los objetos sea fuertemente
tipado. Dentro de la función de comparación en la clase comparadora tendrás
que usar reflexión para sacar el valor de las propiedades a partir de su
nombre.

vi el otro dia que alguien ponia como
generar un objeto de una clase que ya se tenia definida a partr de un
string que se pasaba dinamicamente. Algo asi:
string clase = "Una Clase Mia";
clase Nuevo Objeto = new clase();



Esto se hace con Activator.CreateInstance, pero no es necesario para
hacer las comparaciones, ya que te llegan creados los objetos a comparar,
por lo que no necesitas crear una instancia a partir del nombre.

Si se pudiese enviar un parametro string con el tipo de clase al
Comparision, entonces en este solo habria que hacer algo asi:

public static int Compara(object X, object Y, string clase) // Si
se pudiese hacer q no lo se
{
clase ObjetoX = (clase)X;
clase ObjetoY = (clase)Y;
return ObjetoX.CompareTo(ObjetoY);
//Aunque aqui veo que no sabria que clase es ni si tiene el metodo
CompareTo(); Esto no valdria de primeras
}



Mejor algo parecido a lo siguiente:

public class MiClaseComparadora<Tipo> where Tipo:IComparable :
IComparer<Tipo>
{
public static int Compare<Tipo>(Tipo X, Tipo Y)
{
return X.CompareTo(Y); //Aqui, en lugar de comparar X a Y, meterías
la lógica necesaria para extraer de X y de Y las propiedades que te
interesen y compararlas.
}
}

Lo anterior está escrito mu rápido de memoria y me he podido equivocar
entre IComparer/IComparable o Compare/CompareTo, pero te da una idea de por
dónde van los tiros.

La verdad que lo que he puesto ahi es lo que se me ha ocurrido ahora
mismo y tiene una pinta de fallar por todos lados, ya que no se si
realmente se podria pasar el parametro "clase",



La clase se pasa con Generics, en el tipo del genérico. Si hubiera que
hacerlo en Framework 1, la pasarías com string y usarías Reflexión (y sería
mucho más complicado y no te detectaría los errores en tiempo de
compilación, sino solo en tiempo de ejecución).

que al ser una clase desconocida (puede ser cualquiera) no sabria si
tene el CompareTo() y no nos dejaria utilizarlo.



En Framework 1 sabrías si tiene el CompareTo mediante "if objeto is
IComparable...". En Framewrok 2 usando Generics no es necesario, porque para
eso están las restricciones del Generic (lo que se pone al principio de la
clase detrás del "where..."), que permiten que en tiempo de compilación se
detecte si se está pasando una clase inadecuada.
Respuesta Responder a este mensaje
#5 ANT1
17/01/2007 - 10:59 | Informe spam
Creeme Alberto cuando digo que me impresionas. Me parece increible todo
lo que conoces de C#. No se cuanto llevaras trabajando en esto pero es
impresionante. Yo con mis 4 meses de experiencia lo flipo.

Respecto a todo lo que me cuentas algunas cosillas como la reflexion
escapan a mi entendimiento o si el parametro que hay que pasar a dicha
clase para decir por que propiedad queremos compararle es Type o
String. Ademas mi trabajo con genericos <T> ha sido muy limitado hasta
el momento. Por todo ello me llevara un tiempo mirarme todas esas
lagunas "basicas" que tengo.

No doy por cerrado este hilo porque ten en cuenta que preguntare mas
cosas y dudas que me surjan. Pero tiempo al tiempo.

Muchas gracias.


On 17 ene, 10:07, "Alberto Poblacion"
wrote:
"ANT1" wrote in messagenews:

> [...]
> Empleado.Sort("Nombre"); La forma de hacer esto es esta:

Empleado.Sort(new MiClaseComparadora<Tipo>("Nombre"));

En el constructor de MiClaseComparadora recibes el argumento "Nombre",
lo guardas en una variable privada de la clase, y ya sabes cuál es el campo
que hay que comparar. En <Tipo> le pasas la clase cuyos objetos hay que
comparar, con lo que consigues que el acceso a los objetos sea fuertemente
tipado. Dentro de la función de comparación en la clase comparadora tendrás
que usar reflexión para sacar el valor de las propiedades a partir de su
nombre.

> vi el otro dia que alguien ponia como
> generar un objeto de una clase que ya se tenia definida a partr de un
> string que se pasaba dinamicamente. Algo asi:
> string clase = "Una Clase Mia";
> clase Nuevo Objeto = new clase(); Esto se hace con Activator.CreateInstance, pero no es necesario para
hacer las comparaciones, ya que te llegan creados los objetos a comparar,
por lo que no necesitas crear una instancia a partir del nombre.

> Si se pudiese enviar un parametro string con el tipo de clase al
> Comparision, entonces en este solo habria que hacer algo asi:

> public static int Compara(object X, object Y, string clase) // Si
> se pudiese hacer q no lo se
> {
> clase ObjetoX = (clase)X;
> clase ObjetoY = (clase)Y;
> return ObjetoX.CompareTo(ObjetoY);
> //Aunque aqui veo que no sabria que clase es ni si tiene el metodo
> CompareTo(); Esto no valdria de primeras
> }Mejor algo parecido a lo siguiente:

public class MiClaseComparadora<Tipo> where Tipo:IComparable :
IComparer<Tipo>
{
public static int Compare<Tipo>(Tipo X, Tipo Y)
{
return X.CompareTo(Y); //Aqui, en lugar de comparar X a Y, meterías
la lógica necesaria para extraer de X y de Y las propiedades que te
interesen y compararlas.
}

} Lo anterior está escrito mu rápido de memoria y me he podido equivocar
entre IComparer/IComparable o Compare/CompareTo, pero te da una idea de por
dónde van los tiros.

> La verdad que lo que he puesto ahi es lo que se me ha ocurrido ahora
> mismo y tiene una pinta de fallar por todos lados, ya que no se si
> realmente se podria pasar el parametro "clase", La clase se pasa con Generics, en el tipo del genérico. Si hubiera que
hacerlo en Framework 1, la pasarías com string y usarías Reflexión (y sería
mucho más complicado y no te detectaría los errores en tiempo de
compilación, sino solo en tiempo de ejecución).

> que al ser una clase desconocida (puede ser cualquiera) no sabria si
> tene el CompareTo() y no nos dejaria utilizarlo. En Framework 1 sabrías si tiene el CompareTo mediante "if objeto is
IComparable...". En Framewrok 2 usando Generics no es necesario, porque para
eso están las restricciones del Generic (lo que se pone al principio de la
clase detrás del "where..."), que permiten que en tiempo de compilación se
detecte si se está pasando una clase inadecuada.
Respuesta Responder a este mensaje
Ads by Google
Help Hacer una preguntaSiguiente Respuesta Tengo una respuesta
Search Busqueda sugerida