miércoles, 25 de noviembre de 2015

Operaciones entre Conjuntos: Unión, Intersección y Diferencia

En este post se detallará el código para realizar operaciones entre dos listas, llamadas conjuntos, que contienen como elemento diferentes ciudades y sus respectivas coordenadas geográficas cumpliendo con lo indicado en el programa principal detallado a continuación.

package Deber2;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.LinkedList;
import practica1.Coordenada;

public class Programa {

    public static void main(String[] args) {
        LinkedList<Coordenada> conjunto1 = new LinkedList<>();
        LinkedList<Coordenada> conjunto2 = new LinkedList<>();
        LinkedList<Coordenada> union, interseccion, resta;

        Programa.cargarC1(conjunto1);
        Programa.cargarC2(conjunto2);
        union = Conjunto.union(conjunto1, conjunto2);
        interseccion = Conjunto.interseccion(conjunto1, conjunto2);
        resta = Conjunto.diferencia(conjunto1, conjunto2);
        System.out.println("La unión es:");
        Conjunto.imprimir(union);
        System.out.println("La interseccion es:");
        Conjunto.imprimir(interseccion);
        System.out.println("La diferencia es:");
        Conjunto.imprimir(resta);
     
        Programa.guardar("resultado.txt", union, interseccion, resta);//Guardar en archivo
    }

    private static void cargarC1(LinkedList<Coordenada> conjunto) {
        conjunto.add(new Coordenada(10, 10, "Ciudad 1"));
        conjunto.add(new Coordenada(20, 20, "Ciudad 2"));
        conjunto.add(new Coordenada(30, 30, "Ciudad 3"));
        conjunto.add(new Coordenada(40, 40, "Ciudad 4"));
    }

    private static void cargarC2(LinkedList<Coordenada> conjunto) {
        conjunto.add(new Coordenada(50, 50, "Ciudad 5"));
        conjunto.add(new Coordenada(20, 20, "Ciudad 2"));
        conjunto.add(new Coordenada(60, 60, "Ciudad 6"));
        conjunto.add(new Coordenada(40, 40, "Ciudad 4"));
    }
}


En otro paquete ya tenemos creada nuestra clase Coordenada, en la cual se detalla los atributos: NombredelaCiudad, latitud y longitud.

A continuación tenemos la clase Conjunto en la cual estarán las operaciones que se van a realizar.

   public class Conjunto {

         public static LinkedList<Coordenada> union(LinkedList<Coordenada> conjunto1,            

                                                                                     LinkedList<Coordenada> conjunto2) {

        LinkedList<Coordenada> union = new LinkedList<>(conjunto1);
        boolean encontrado = false;
        for (Coordenada coordenada2 : conjunto2) {
            for (Coordenada coordenada1 : conjunto1) {
                if (coordenada2.ciudad.equals(coordenada1.ciudad)) {
                    encontrado = true;
                    break;
                }
            }
            if (!encontrado) {
                union.add(coordenada2);
            } else {
                encontrado = false;
            }
        }
        return union;
    }

El primer método es unión, como podemos observar este método devuelve como parámetro una lista de tipo Coordenada (LinkedList<Coordenada> ) y recibe como parámetro las 2 listas: conjunto 1 y conjunto 2 (LinkedList<Coordenada> conjunto1, LinkedList<Coordenada> conjunto2)
Para realizar la operación de unión, primero creamos una nueva lista union la cual contiene los elementos de la lista conjunto1. Luego por medio de una sentencia for, se va recorrer la lista conjunto 2, dentro de este for se crea la variable coordenada2 que es de tipo Coordenada y que representa cada elemento de esta lista, con otra sentencia for recorremos la lista conjunto1, es decir que cuando toma el primer elemento de la lista 2 va recorrer toda la lista 1 y así hasta llegar hasta el ultimo elemento de la lista2. Con una sentencia if vamos a comparar los elementos de la listas y usamos el método equals, al usar este método tuve un  error ya lo use de la siguiente manera:
                                              if (coordenada2.equals(coordenada1))
y mi resultado fue el siguiente:


Como podemos observar las ciudades 2 y 4, que están en ambas listas se repiten debido a que con el método usado de esta manera no esta comparando el elemento de la lista sino que si los objetos son producto de la misma instancia es decir esta comparando su referencia de memoria.
La forma correcta para esta operación seria:
                               if (coordenada2.ciudad.equals(coordenada1.ciudad))
En la cual indico uno de los atributos de la lista para comparar.

Si se encuentran los valores iguales, mi variable encontrado (tipo boolean) es verdadera y con el break sale del segundo for, sino sigue buscando y en ambos casos pregunto si coordenada es falso entonces añado el elemento del conjunto2 a mi lista union por medio del método add, sino hago que encontrado sea falso para que siga buscando.

Y retorno mi lista union.



    public static LinkedList<Coordenada> interseccion(LinkedList<Coordenada> conjunto1, LinkedList<Coordenada> conjunto2) {

        LinkedList<Coordenada> interseccion = new LinkedList<>();
        boolean encontrado = false;
        for (Coordenada coordenada2 : conjunto2) {
            for (Coordenada coordenada1 : conjunto1) {
                if (coordenada2.ciudad.equals(coordenada1.ciudad)) {
                    encontrado = true;
                    break;
                }
            }
            if (encontrado) {
                interseccion.add(coordenada2);
                encontrado = false;
            }
        }
 
    return interseccion ;
}

El segundo método es intersección, el cual también devuelve como parámetro una lista de tipo Coordenada (LinkedList<Coordenada> ) y recibe como parámetro las 2 listas: conjunto 1 y conjunto 2 (LinkedList<Coordenada> conjunto1, LinkedList<Coordenada> conjunto2).

Para realizar la intersección, creamos una lista interseccion vacía, y realizamos la sentencia for anteriormente indicada, pero cuando el encontrado es verdadero se añade a la lista interseccion el elemento coordenada2 que se igual al de conjunto1, luego hacemos que encontrado sea falso para poder seguir con la búsqueda. Y retornamos la lista intersección



    public static LinkedList<Coordenada> diferencia(LinkedList<Coordenada> conjunto1, LinkedList<Coordenada> conjunto2) {

        LinkedList<Coordenada> diferencia = new LinkedList<>();
        boolean encontrado = false;
        for (Coordenada coordenada1 : conjunto1) {
            for (Coordenada coordenada2 : conjunto2) {
                if (coordenada2.ciudad.equals(coordenada1.ciudad)) {
                    encontrado = true;
                    break;
                }
            }
            if (!encontrado) {
                diferencia.add(coordenada1);}
            else{
                encontrado=false;}
            }
       
 
    return diferencia;
}

El tercer método es diferencia, el cual también devuelve y recibe los mismo parámetros que en los métodos anteriores.

En este metodo se va realizar la difrencia A-B es decir Conjunto 1 - Conjunto2 y obtendremos los valores de conjunto1 que son diferentes al conjunto 2, para esto el primer for es para recorrer el conjunto1. Para realizar la diferencia, creamos una lista diferencia vacía, y realizamos la sentencia for anteriormente indicada, pero cuando encontrado es falso se añade a la lista diferencia el elemento coordenada1 que sea diferente al del conjunto2.  Y retornamos la lista diferencia.


Para imprimir las listas usamos el siguiente metodo, el cual se usa una sentencia for, para que imprima uno por uno cada elemento.

public static void imprimir(LinkedList<Coordenada> lista) {
        for(Coordenada c:lista)
                System.out.println(c);
    }

}

Para cargar las listas desde un archivo se define lo siguiente en el programa principal y a su vez se realiza el siguiente método cargar:
     
        conjunto1 = Programa.cargar("Ciudades1.txt");
        conjunto2 = Programa.cargar("Ciudades2.txt");


(public static LinkedList<Coordenada> cargar(String archivo) {

        FileReader fr;
        BufferedReader br = null;
        String linea;
        String datos[];
        Coordenada coor;
        LinkedList<Coordenada> list = new LinkedList<>();

        try { //Se coloca una sentencia try-catch para el momento en que haya error no se caiga el                                                        programa sino que envíe un mensaje de error
            fr = new FileReader(archivo);//Puntero para leer el archivo
            br = new BufferedReader(fr);//Guardar el texto que se esta apuntando en el archivo

            while ((linea = br.readLine()) != null) { //Asignamos linea por linea el texto hasta que sea                                                                                     hasta que llega al final del archivo
                datos = linea.split(",");// Aquí indicamos que cada elemento de la lista va estar
                                                       separado por una coma
                coor = new Coordenada();
                coor.ciudad = datos[0]; //indicamos que ciudad es el primer dato                                            
                coor.latitud = Float.parseFloat(datos[1]); // se usa el para hacer conversiones de tipo de                                                                                            datos e indicamos que latitud sera el                                                                                                          segundo dato
                coor.longitud = Float.parseFloat(datos[2]);// indicamos que longitud es el tercer dato  
                list.add(coor); //añadimos los elementos a la lista
            }

        } catch (FileNotFoundException ex) {
            System.out.println("El archivo no existe");
        } catch (IOException ex) {

            System.out.println("Error de lectura del archivo");
        }

        return list;
    }
y para guardar en un archivo .txt tenemos el siguiente metodo: guardar

public static void guardar(String archivo, LinkedList<Coordenada> union,  LinkedList<Coordenada> interseccion,LinkedList<Coordenada> diferencia )

 throws IOException {

        File f;
        FileWriter fw;
        PrintWriter pw= null;

        try {
            f= new File(archivo);
            fw = new FileWriter(f);
            pw = new PrintWriter(fw);

            for (int i=0; i<3; i++){
                if(i==0){
                    pw.println("Unión:"+union);
                }
                else if (i==1){
                   pw.println("Interseccion:"+interseccion);
                }
                else if (i==2){
                    pw.println("Resta:"+diferencia);
                }
            }

        }catch(FileNotFoundException ex) {
            System.out.println("");
        } finally {
            if(pw!=null)
                pw.close();
        }
    }