Autor Tema: Problema utilizando TreeSet Java solo introduce primer elemento o item no resto  (Leído 2821 veces)

usuHelp

  • Sin experiencia
  • *
  • APR2.COM
  • Mensajes: 3
    • Ver Perfil
Hola, una consulta sobre Java.

Teniendo esta clase Jugador:
Código: [Seleccionar]
public class Jugador implements Comparable<Jugador>{
private String nombre, id;

public Jugador(){
this( "", ""); // llama al constructor con dos argumentos
}
public Jugador(String id,String nombre) {
this.id= id;
this .nombre=nombre;
}
public String getNombre(){
return nombre;
}
public void setNombre (String nombre) {
this.nombre = nombre;
}
public void setId(String id ) {
this.id=id;
}

public String getId( ) {
return id;
}
public void mostrar Datos( ) {
System.out.println( "ID: "+id+"\nNombre: "+nombre);
}
@Override
public int compareTo(Jugador o) {
// TOTO Auto-generated method stub
return 0;
}

En el main intento introducir datos de jugadores, introducirlos en un TreeSet e imprimirlos,el problema es que solo introduce el primero. Por ejemplo:

Código: [Seleccionar]
TreeSet <Jugador> listaJugadores = new TreeSet<Jugador>();
Jugador j1 = new Jugador("jA","pepe");
Jugador j2 = new Jugador("jB","juan");
Jugador j3 = new Jugador("jC","maria");
listaJugadores.add(j1);
listaJugadores.add(j2);
listaJugadores.add(j3);

for(Jugador j: listaJugadores) {
j.mostrarDatos();
}

Solo muestra jA Pepe.Gracias por adelantado!
« Última modificación: 16 de Abril 2021, 19:20 por Ogramar »

Kabuto

  • Moderador Global
  • Experto
  • *******
  • Mensajes: 989
    • Ver Perfil
Re: Problema utilizando TreeSet
« Respuesta #1 en: 02 de Enero 2021, 14:40 »
Hola,
se debe a que no has completado el método compareTo()

Verás, el TreeSet tiene una peculiaridad y es que SOLO admite elementos que NO estén repetidos.
Pero claro, él por si solo, no es capaz de discernir cuándo un elemento se repite o no.

En este caso trabajamos con objetos Jugador., ¿Cuándo un Jugador es igual a otro?
¿Cuando tienen el mismo nombre?
¿Cuando tiene el mismo ID?
¿Cuando coinciden tanto el nombre como el ID?

Esto TreeSet no lo puede decidir, lo decide el programador
Una forma de hacerlo, es implementando la interfaz Comparable a la clase que está creando.

A Jugador, le has implementado dicha interfaz, bién,  pero no has completado el método compareTo().
Así que no has decidido todavía cómo se han de comparar los objetos Jugador.

Has dejado el código que viene por defecto, que hace un return 0.

Código: [Seleccionar]
@Override
public int compareTo(Jugador o) {
// TODO Auto-generated method stub
return 0;
}
Y cuando compareTo() retorna 0, significa que los objetos que se comparan son iguales.

Por tanto, el TreeSet confía ciegamente en lo que este método le dice, y le está diciendo que todos los objetos Jugador que le estás pasando, son iguales.
Y por tanto, el TreeSet solo admite el primero y el resto los rechaza.

Esto se puede comprobar muy fácilmente. Cuando añadimos un objeto al TreeSet, este retorna true si lo admite o false si lo rechaza.
Si pedimos mostrar en pantalla qué es lo que retorna cada vez que hacemos un add()...
Citar
   public static void main(String[] args) {
      
      TreeSet <Jugador> listaJugadores = new TreeSet<Jugador>();
         Jugador j1 = new Jugador("jA","pepe");
         Jugador j2 = new Jugador("jB","juan");
         Jugador j3 = new Jugador("jC","maria");
         System.out.println(listaJugadores.add(j1));
         System.out.println(listaJugadores.add(j2));
         System.out.println(listaJugadores.add(j3));

        
         for(Jugador j: listaJugadores) {
            j.mostrarDatos();
         }

   }

...veremos que solo admite el primero:
Citar
true
false
false
ID: jA
Nombre: pepe

Podemos hacer otro experimento, cambiamos el método compareTo() para que retorne algo que no sea 0:
Citar
   @Override
   public int compareTo(Jugador o) {
      // TODO Auto-generated method stub
      return 1;
   }

Cuando retorna un entero positivo, como el 1, significa que el objeto que recibe como argumento para compararse, es mayor. Por tanto, no son iguales, así que ahora TreeSet si admitirá los tres objetos que le pasamos (aunque en realidad aún no hemos establecido una regla de comparación que sea útil)
Si volvemos a ejecutar el programa, veremos que los tres objetos añadidos retornan true y podemos listarlos en pantalla:
Citar
true
true
true
ID: jA
Nombre: pepe
ID: jB
Nombre: juan
ID: jC
Nombre: maria

Aprovechemos la ocasión para hacer otro experimento. Volvemos a cambiar el retorno de compareTo(), esta vez, vamos a pedir que retorne un valor negativo.
Citar
   @Override
   public int compareTo(Jugador o) {
      // TODO Auto-generated method stub
      return -1;
   }

Un valor negativo significa que el objeto que recibe como argumento para compararse, es menor.
¿Qué pasa entonces si volvemos a ejecutar el programa?
Citar
true
true
true
ID: jC
Nombre: maria
ID: jB
Nombre: juan
ID: jA
Nombre: pepe

¡¡Voilá!!
Los tres Jugadores se han añadido y además se han ordenado de forma inversa a la que los hemos insertado.
Esto es porque ahora compareTo() le está diciendo a TreeSet que todas las comparaciones resultan en que el nuevo objeto recibido es menor respecto a los que ya hay insertados.

Esta es otra peculiaridad de TreeSet, no solo evita que se repitan elementos, si no que siempre los tiene ordenados de menor a mayor.

La verdad es que este tipo de Set es un encanto  :-* je je.
Pero claro, para que lo haga bien, nosotros tenemos que escribir correctamente el método compareTo() y decidir cuáles son las reglas de comparación para nuestra clase.

La pregunta es:
¿Cuándo podemos considerar un Jugador menor o mayor que otro?

Puede depende de cada caso y del criterio del programador, por supuesto..

En este caso, comos los jugadores tienen un ID, que se supone ha de ser único, pues puede ser ese el atributo que consideremos fundamental para comparar Jugadores.

Ahora hay que escribir un código para decidir como compara ese atributo.
Puesto que se trata de un String, y la clase String ya tiene implementada su propia regla de comparación, pues podemos simplemente establecer que se retorne el resultado de comparar los ID, tal cuál establece la clase String:
Citar
   @Override
   public int compareTo(Jugador o) {
      return this.id.compareTo(o.id);
   }

Los String hacen una comparación lexicográfica, es decir, que la letra a se considera menor que la b, la b es menor que la c, etc..

Vamos, que ordena alfabéticamente de la a a la z, y según cuantas letras tiene cada String.

Si volvemos a ejecutar el programa, y cambiamos los id para insertarlos desordenados alfabéticamente:

Citar
   public static void main(String[] args) {
      
      TreeSet <Jugador> listaJugadores = new TreeSet<Jugador>();
         Jugador j1 = new Jugador("jB","pepe");
         Jugador j2 = new Jugador("jC","juan");
         Jugador j3 = new Jugador("jA","maria");
         System.out.println(listaJugadores.add(j1));
         System.out.println(listaJugadores.add(j2));
         System.out.println(listaJugadores.add(j3));
        
         for(Jugador j: listaJugadores) {
            j.mostrarDatos();
         }

   }

Veremos que al mostrarlos, se muestran bien ordenados:
Citar
true
true
true
ID: jA
Nombre: maria
ID: jB
Nombre: pepe
ID: jC
Nombre: juan
NO respondo dudas por mensaje privado
Publicando vuestras dudas en el foro público conseguimos:
- Que más gente aporte respuestas mejores o complementarias.
- Que otras personas puedan aprender de vuestras dudas.

Mejor en PÚBLICO que en privado. Gracias

usuHelp

  • Sin experiencia
  • *
  • APR2.COM
  • Mensajes: 3
    • Ver Perfil
Re: Problema utilizando TreeSet
« Respuesta #2 en: 05 de Enero 2021, 00:24 »
Muchas gracias! Ahora me surge otra duda,hay alguna manera de comparar constantes declaradas en una interfaz? Por ejemplo, si tengo subclases con la super como jugador, y en esas subclases tengo las variables declaradas de la interfaz,cada constante calculada de una distinta manera en cada subclase(dependen de los distintos métodos introducidos en cada subclase).Teniendo un ArrayList<Jugador> lleno de los distintos tipos(de las subclases) y los quiero ordenar  según una caracteristica que tienen en común,la constante extendida de la interfaz,hay alguna manera de hacer eso? Ya que id o nombre no hay ningún problema pero con las compartidas de la interfaz sí,entiendo que son conceptos distintos pero no soy capaz de llegar a ninguna solución...Gracias!

Kabuto

  • Moderador Global
  • Experto
  • *******
  • Mensajes: 989
    • Ver Perfil
Re: Problema utilizando TreeSet
« Respuesta #3 en: 06 de Enero 2021, 00:13 »
Mmmhhh.. pues posiblemente sí, aunque puede ser algo más complicado.

Si la interfaz la implementa la clase Jugador, y por tanto esta clase tendría esas constantes dentro de su ámbito, entonces si deberían poder usarse como regla de comparación.

Si la interfaz la implementase las clases hijas, y no Jugador, la cosa se complicaría más.
Porque los objetos que están el <Jugador>TreeSet en ese momento son objetos de clase Jugador, que no implementa esa interfaz y por tanto las constantes están fuera de su ámbito. Vamos, que no tiene ni idea de que constantes son.

Habría que complicar un poco el código preguntando en cada caso que tipo de clase hija pertenece con la palabra reservada instanceof y hacer un casting para convertirlo a la clase hija a la que realmente pertenece dicho objeto, y ahora sí se podrían consultar esas constantes.

Si compartes todo tu código, podemos intentar ver cuál sería la mejor solución.
NO respondo dudas por mensaje privado
Publicando vuestras dudas en el foro público conseguimos:
- Que más gente aporte respuestas mejores o complementarias.
- Que otras personas puedan aprender de vuestras dudas.

Mejor en PÚBLICO que en privado. Gracias

 

Sobre la educación, sólo puedo decir que es el tema más importante en el que nosotros, como pueblo, debemos involucrarnos.

Abraham Lincoln (1808-1865) Presidente estadounidense.

aprenderaprogramar.com: Desde 2006 comprometidos con la didáctica y divulgación de la programación

Preguntas y respuestas

¿Cómo establecer o cambiar la imagen asociada (avatar) de usuario?
  1. Inicia sesión con tu nombre de usuario y contraseña.
  2. Pulsa en perfil --> perfil del foro
  3. Elige la imagen personalizada que quieras usar. Puedes escogerla de una galería de imágenes o subirla desde tu ordenador.
  4. En la parte final de la página pulsa el botón "cambiar perfil".