Autor Tema: Java: modificar lista ArrayList mientras se recorre o itera añadir elemento add  (Leído 32182 veces)

LPM

  • Sin experiencia
  • *
  • APR2.COM
  • Mensajes: 35
    • Ver Perfil
Hola.

Estaba practicando con un ejercicio del curso de Java. Era pedir agregar por teclado elementos a un arrayList.

Lo que quise hacer era tomar la primer letra del valor que se ingresa con el método substring, recorrer el array con el bucle foreach  y comparándolo con la primer letra de cada elemento.

Elegí substring porque comparar 1 letra parece mas fácil, o mas simple. Bueno, en el momento en que la letra del valor fuera mayor que la de algún elemento, uso el método get, le paso como parámetro el elemento comparado en el momento y le sumo +1 para ponerlo después de ese.

Sería algo así:

lista.add(elemento+1,valorTeclado);
break;

Break para terminar el bucle porque ya se agregó a la lista. Pero si no es mayor que ninguno, entonces es el menor de todos.

if(valorTeclado>elemento){lista.add(elemento+1,valorTeclado);
break;}
else {lista.add(0,valorTeclado)}

Para comparar encontré el método compareTo, pero hace hooooras estoy probando y probando y no me sale. Hasta se me fue de las manos esto. Me pide escribir incluso sin haber importado la clase Scanner.

Copié la clase a un nuevo paquete, por las dudas, tal vez había algo que no veía o que toqué, pero igual, me sigue pidiendo escribir!

Código: [Seleccionar]
import java.util.ArrayList;
//import java.util.Scanner;

public class ListaCantantesFamosos
{    private ArrayList<String>listaCantantes;
   
    public ListaCantantesFamosos(){
       listaCantantes=new ArrayList<String>(){{add("Bara");add("Maria");add("Tario");}};
    }
     
    public void ordenado(){
       //Scanner teclado=new Scanner(System.in);
       System.out.println("Escriba:");
       String cantante="Tola";//teclado.nextLine();
       for(int i=0;i<listaCantantes.size();i++){
           if (cantante.compareTo(listaCantantes.get(i))>0){
               listaCantantes.add(i+1,cantante);
               break;   
           }else{listaCantantes.add(0,cantante);}
       }
       System.out.println(listaCantantes);
    }
}

Dejé comentado lo referente a Scanner porque la idea es escribir y encontrarle una posición en el array. También saqué el substring por las dudas, cuando ya no se te ocurre nada hacés cualquier cosa xd

Probé en otra clase el compareTo, y funciona bien.

Código: [Seleccionar]
public class Casd
{
    public static void main(String[]args){
        String a="abc";
        String b="bca";
        String c="cba";
        if (a.compareTo(b)>0){
            System.out.println("a Es mayor que b");
        }else{System.out.println("a Es menor que b");}
        if (b.compareTo(c)>0){
            System.out.println("b Es mayor que c");
        }else{System.out.println("b Es menor que c");}
        if (c.compareTo(a)>0){
            System.out.println("c Es mayor que a");
        }else{System.out.println("c Es menor que a");}
    }
}

Probé con el for común y el iterator, por si estaba mal el usar foreach para lo que quería. No compilabra primero, luego compilaba, ejecutaba y me tiraba error. Luego terminaba agregando el valor, pero no ordenado. Y ahora me pide que le de y le de... entradas... por teclado xd

Bueno, en esta clase hice 3 métodos: for, foreach e iterator.

Código: [Seleccionar]
import java.util.ArrayList;
import java.util.Scanner;
import java.util.Iterator;

public class ListaCantantesFamosos3{
    private ArrayList<String>listaCantantes;
    private ArrayList<String>listaCantantes2;
   
    public ListaCantantesFamosos3(){
        listaCantantes=new ArrayList<String>(){{add("Bara");add("Maria");add("Tario");}};
    }
   
    public void ordenado(){
       Scanner teclado=new Scanner(System.in);
       System.out.println("Escriba:");
       String cantante=teclado.nextLine();
       for(int i=0;i<listaCantantes.size();i++){
           if (cantante.substring(0,1).compareTo(listaCantantes.get(i).substring(0,1))<0){
               listaCantantes.add(i+1,cantante);
               break;   
           }else{listaCantantes.add(0,cantante);}
       }
       System.out.println(listaCantantes);
    }

    /*
     
    public void ordenado(){
       Scanner teclado=new Scanner(System.in);
       System.out.println("Escriba:");
       String cantante=teclado.nextLine();
       for (String elemento:listaCantantes){
           if (cantante.compareTo(elemento)>0){
               listaCantantes.add(listaCantantes.indexOf(elemento)+1,cantante);
               break;
           }else{listaCantantes.add(0,cantante);
            break;}
         }
    }
    */
   
    /*public void ordernadoITR(){
    Iterator<String> listaITR=listaCantantes.iterator();
    Scanner teclado=new Scanner(System.in);
    System.out.println("Escriba:");
    String cantante=teclado.nextLine();
    while(listaITR.hasNext()){
        String elemento=listaITR.next();
        if (cantante.compareTo(elemento)>0){
            listaCantantes.add(listaCantantes.indexOf(elemento)+1,cantante);
        }else{listaCantantes.add(0,cantante);}
        }
    }
    */
}

No se exactamente si pide que escriba, pero me deja escribir en la ventana "terminal" de blueJ, como si así fuera.

Miré la clase en la api, pero... me costó entender. No pude sacar algo en concreto. Solo que compara y devuelve un int según si es menor, igual o mayor.

Encontré el método sort, pero probé el compareTo con algo sencillo. Y debería funcionar con lo que quiero, o no? Qué hago mal? No entiendo

Una última cosa... al principio tenía la clase ListaCantantes, que la declaraba en otra clase, ponele TestLista, de modo que alguien escriba para usar el programa. El problema es que en la clase TestLista no podía trabajar con el array directamente. Tenía que declarar métodos en la clase ListaCantantes e invocarlos en TestLista.

Por ejemplo, un método que me diga cuántos elementos hay en la lista usando como retorno el método size. Si lo creo en TestLista dice que no encuentra el método.  No se si alguien me puede explicar esto, dejo archivado las 2 clases, por si hace falta.



Bueno, espero que no haya quedado algo suelto, y que se entienda. Cualquier respuesta es bienvenida =)
« Última modificación: 04 de Diciembre 2014, 11:50 por Alex Rodríguez »

LPM

  • Sin experiencia
  • *
  • APR2.COM
  • Mensajes: 35
    • Ver Perfil
Re:Java - Usar compareTo al pedir un String y posicionarlo en un array
« Respuesta #1 en: 02 de Diciembre 2014, 19:32 »
No me deja editar el post.

Estaba mirando que las condiciones estaban mal, debe ser ese el problema.

Lo arreglo y pongo el código

------------------

Funciona!

Código: [Seleccionar]
import java.util.ArrayList;
import java.util.Scanner;
import java.util.Iterator;

public class ListaOrdenada{
    private ArrayList<String>listaO;
       
    public ListaOrdenada(){
        listaO=new ArrayList<String>(){{add("Bara");add("Maria");add("Tario");}};
    }
       
    public void ordenadoFor(){
       Scanner teclado=new Scanner(System.in);
       System.out.println("Escriba:");
       String nombre=teclado.nextLine();
       if (nombre.compareToIgnoreCase(listaO.get(0))<0){
           listaO.add(0,nombre);
       }else if(nombre.compareToIgnoreCase(listaO.get(listaO.size()-1))>=0){
           listaO.add(nombre);
       }else for(int i=1;i<listaO.size();i++){
           if (nombre.compareToIgnoreCase(listaO.get(i))<0&&nombre.compareToIgnoreCase(listaO.get(i-1))>=0){
               listaO.add(i,nombre);
               break;
           }
       }
       System.out.println(listaO);
    }
     
    public void ordenadoForEach(){
       Scanner teclado=new Scanner(System.in);
       System.out.println("Escriba:");
       String nombre=teclado.nextLine();
       if (nombre.compareToIgnoreCase(listaO.get(0))<0){
           listaO.add(0,nombre);
       }else if(nombre.compareToIgnoreCase(listaO.get(listaO.size()-1))>=0){
           listaO.add(nombre);
       }else for (String elemento:listaO){
           if (nombre.compareToIgnoreCase(listaO.get(0))>=0&&nombre.compareToIgnoreCase(listaO.get(listaO.indexOf(elemento)+1))<0){
               listaO.add(listaO.indexOf(elemento)+1,nombre);
               break;
           }
       }
    }
   
    public void ordernadoITR(){
        Iterator<String> listaITR=listaO.iterator();
        Scanner teclado=new Scanner(System.in);
        System.out.println("Escriba:");
        String nombre=teclado.nextLine();
        if (nombre.compareToIgnoreCase(listaO.get(0))<0){
            listaO.add(0,nombre);
        }else if(nombre.compareToIgnoreCase(listaO.get(listaO.size()-1))>=0){
            listaO.add(nombre);
        }else while(listaITR.hasNext()){
            String elemento=listaITR.next();
            if (nombre.compareToIgnoreCase(listaO.get(listaO.indexOf(elemento)))>=0&&nombre.compareToIgnoreCase(listaO.get(listaO.indexOf(elemento)+1))<0){
                listaO.add(listaO.indexOf(elemento)+1,nombre);
                break;
            }
        }
        System.out.println(listaO);
    }
}


Encima se puede usar else for! Me queda probar con Iterator.

Funciona, pero no se si estará bien el constructor, o si se puede mejorar algo.
« Última modificación: 02 de Diciembre 2014, 20:46 por LPM »

Alex Rodríguez

  • Moderador Global
  • Experto
  • *******
  • Mensajes: 2052
    • Ver Perfil
Re:Java - Usar compareTo al pedir un String y posicionarlo en un array
« Respuesta #2 en: 04 de Diciembre 2014, 11:28 »
Hola, he estado revisando tu código y tus explicaciones y me ha resultado bastante difícil de seguir debido a que es extenso y hablas de muchas cosas. Como recomendación: escribe mensajes donde definas con precisión lo que quieres hacer y el punto concreto donde tienes el problema. Una vez resuelto ese punto concreto, responde introduciendo el siguiente código o siguiente problema. En este caso podrías haber ido tratando primero una forma de recorrer y cuando estuviera comentada y aclarada pasar a la siguiente. Así sería más fácil revisar y encontrar solución a los problemas, ya que al leer todo junto se hace incomprensible o difícil de entender (con lo cual la gente no responderá porque no entiende).

Sobre tu código de ListaOrdenada te digo lo siguiente:

Tratas de hacer algo que parece sencillo pero tiene su complicación, que es la modificación de una colección de elementos al mismo tiempo que la recorres (modificación concurrente).

Normalmente diría que el enfoque que se le suele dar a esto es distinto: digamos que el enfoque más habitual sería añadir lo que quieras añadir a la lista, después ordenarla con el criterio con que quieras ordenarla y ya está.

Pero supongamos que queremos hacer una modificación concurrente.

En el método ordenado For usas una comparación para comprobar si la palabra sería la primera de la lista y en ese caso insertas la palabra la primera de la lista, luego otra comparación para comprobar si la palabra sería la última de la lista y en ese caso insertas la palabra la última de la lista. Por último, otra comparación en caso de que no se cumpla ninguna de las dos condiciones anteriores donde recorres todas las palabras menos la primera y la última, compruebas que  la palabra tendría que colocarse entre la actual que recorres y la siguiente. Si es así, insertas la palabra en la posición en que te encuentras (desplazando así las palabras mayores hacia delante en la lista).

Esto está bien pensado, pero un programador con experiencia no estaría muy de acuerdo con este código porque no se ve eficiente. Te voy a indicar por qué para que trates de razonarlo y ver si llegas a las mismas conclusiones:

- Si puedes recorrer toda la lista usando un for, no parece necesario comprobar el primer y último elemento de la lista por separado, ya que podemos hacerlo dentro del for. Esto hace el código más corto y más fácil de entender (cosa valorada en un programador).

Para ello debemos empezar a buscar en el bucle por el 0 en lugar de por el 1 (así incluimos el primer elemento)

Para saber si estamos en el primer o último elemento podemos usar el valor de i. Si es cero es el primer elemento de la lista y hacemos un análisis especial porque no tenemos elemento anterior en la lista.

Si es el último elemento de la lista no tenemos que hacer nada especial porque sí tenemos elemento anterior en la lista.


El código quedaría así:

Código: [Seleccionar]
       for(int i=0;i<listaO.size();i++){
           if (i==0 && nombre.compareToIgnoreCase(listaO.get(i))<0) {listaO.add(i,nombre); break; }
           if (i!=0 && nombre.compareToIgnoreCase(listaO.get(i))<0&&nombre.compareToIgnoreCase(listaO.get(i-1))>=0){
               listaO.add(i,nombre); break;
           }
           if (i==listaO.size()-1  ) { //&& nombre.compareToIgnoreCase(listaO.get(i))>=0
               listaO.add(nombre); break;
            }
       }


Pero algunos programadores no estarían muy conformes con esto por el uso de break; dentro de bucles for se suele considerar poco elegante utilizar break.

Otros programadores dirían que estamos manipulando una colección mientras la recorremos con un bucle for y esto es "no seguro". De hecho si eliminas los break puedes entrar en un bucle infinito, porque al mismo tiempo que recorres la colección la modificas y listaO.size() va cambiando, los índices de los elementos cambian... lo cual se dice que es programación insegura.

El recorrido seguro que permite modificaciones concurrentes se logra mediante iteradores. Pero si usamos un iterador normal, nos permite eliminar elementos a la colección pero no añadirlos.

En cambio un iterador de tipo ListIterator sí nos permite añadir elementos (ver https://docs.oracle.com/javase/8/docs/api/java/util/ListIterator.html)

Con esto, podríamos usar este código:

Código: [Seleccionar]
    public void ordernadoITR(){
        ListIterator<String> listaITR=listaO.listIterator();
        Scanner teclado=new Scanner(System.in);
        System.out.print("Escriba nombre: ");
        String nombre=teclado.nextLine();
        boolean yaHaSidoInsertado=false;
        while(listaITR.hasNext() && yaHaSidoInsertado==false){

            if (nombre.compareToIgnoreCase(listaITR.next())<0 && yaHaSidoInsertado==false){
                listaITR.previous();
                listaITR.add(nombre); //Insertamos
                yaHaSidoInsertado=true;

            }     
        }
        if (yaHaSidoInsertado == false) { listaO.add(nombre);}//Si no se insertó antes de algún elemento existente lo insertamos al final
        System.out.println(listaO);
    }

Con esto hemos dejado de usar break (que no suele recomendarse, aunque tampoco es algo prohibido).

Habría más formas de hacerlo y de enfocarlo, espero que lo comentado te sirva de ayuda.

Saludos

LPM

  • Sin experiencia
  • *
  • APR2.COM
  • Mensajes: 35
    • Ver Perfil
Hola alex

Quise editar el mensaje pero no me dejó. A la próxima haré como decís



Con lo del código, quería ordenarlo luego de ingresar un elemento. A mitad del trabajo encontré el método sort, pero quise terminar usando los bucles y condicionales para aprender.

No le encontraba la vuelta. Ahora que veo el tuyo usando el for y los if, me quedó claro.

Gracias por la ayuda.



 

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".