Perl en Español

  1. Home
  2. Tutoriales
  3. Foro
  4. Artículos
  5. Donativos
  6. Publicidad
 

Comparar dos columnas de archivos diferentes

 
Publicar nuevo tema   Responder al tema    Foros de discusión -> Básico
Mensaje Sab Jul 12, 2008 11:31 am
Lugerius
Perlero Nuevo
Perlero Nuevo
Registrado: 12 Jul 2008
Mensajes: 5
Comparar dos columnas de archivos diferentes Responder citando

¡Saludos a todos desde México!

Estoy empezando con Perl y estoy batallando mucho con este programita. Rolling Eyes
Tengo dos archivos de texto con el siguiente formato,
Archivo1.txt
Código:
AC000000000   0   0
AC100000000   0   0
AC1100KLP00   19   51.72
AC3030GEN15   7   30.91
AC4015GEN04   11   4.83
AC4017GEN04   0   4.41
AC4017GEN05   24   5.54
AC5001GEN05   66   6.68
AC5002FPC09   15   28.78
AC5002GEN05   16   8.88
AC5003GEN00   6   6.11
AC700000000   0   0


Archivo2.txt
Código:
AC1100KLP00   761.91   19
AC1300GEN06   #N/A    #N/A
AC2100GEN05   #N/A           #N/A
AC3030GEN15   49.77   7
AC3030GEN60   #N/A           #N/A
AC4015GEN04   81.65   12
AC4017GEN04   #N/A           #N/A
AC4017GEN05   93.65   24
AC5001GEN05   10.75   23


Lo que quiero que el programa haga es que cada uno de los elementos de la columna 1 del archivo1.txt se compare con todos los elementos de la columna 1 del archivo2.txt y cuando sean iguales escribir en un nuevo archivo3.txt el contenido de esas filas del archivo1.txt. Espero haberme explicado.

Es decir, en mi ejemplo el archivo3.txt debería quedar más o menos así:
Código:
AC1100KLP00   19   51.72
AC3030GEN15   7   30.91
AC4015GEN04   11   4.83
AC4017GEN04   0   4.41
AC4017GEN05   24   5.54
AC5001GEN05   66   6.68


Donde tengo la duda principalmente es en el algoritmo para comparar los elementos de las columnas 1 de los dos archivos.

No pongo código porque estoy bastante perdido en este asunto, no sé si con un while o metiendo las columnas en arreglos y con foreach, pero he intentado varias cosas y no obtengo los resultados esperados.

De este mismo foro, leí que podía pegar mis archivos en uno solo con el comando paste, pero aún así no sé cómo comparar completamente las dos columnas.

Espero puedan ayudarme y de antemano ¡gracias!

Atte.
Luis G. Mendoza
Mensaje Sab Jul 12, 2008 12:06 pm
explorer
Moderador
Moderador
Registrado: 24 Jul 2005
Mensajes: 3907
Ubicación: Valladolid, España
Responder citando

Bienvenido a los foros de Perl en Español, Lugerius.

Pues tienes razón. Con un while y un hash, tienes solucionado el problema.

Si pones el código te podemos ir dando más pistas.

Aquí te pongo la solución, en forma de pseudocódigo.

Perl:
#!/usr/bin/perl
use strict;
use warnings;
use diagnostics;

# Leemos el fichero Archivo2 y almacenamos la primera columna como claves
# Abrimos los ficheros Archivo1 en lectura y Archivo3 en escritura
# Para todas las líneas de Archivo1
# Si la primera columna de Archivo1 está entre las claves de Archivo2
#   Escribimos la línea de Archivo1 en el Archivo3
# Fin del bucle
# Cerramos los archivos abiertos
Mensaje Sab Jul 12, 2008 12:27 pm
Lugerius
Perlero Nuevo
Perlero Nuevo
Registrado: 12 Jul 2008
Mensajes: 5
Responder citando

Muchas gracias por tu ayuda, voy a leer un poco más sobre los hash y en cuanto tenga el código lo publico.

¡SALUDOS!

Atte.
Luis G. Mendoza
Mensaje Sab Jul 12, 2008 4:51 pm
Lugerius
Perlero Nuevo
Perlero Nuevo
Registrado: 12 Jul 2008
Mensajes: 5
Otra cosa Responder citando

Bueno ya funciona el script pero me parece que no es la mejor forma de hacerlo, de todas formas aquí pongo el código.

Perl:
# Leemos el fichero Archivo2 y almacenamos la primera columna como claves
open(ORIG,"archivo2.txt");
our %hash = ();
our $elemento;
while ($elemento=<ORIG>){
chomp($elemento);
my @linea = (split "\t",$elemento);
$hash{$linea[0]} = 1;
} 
# Abrimos los ficheros Archivo1 en lectura y Archivo3 en escritura
open(DATOS,"archivo1.txt");
open(OUT,">archivo3.csv");
# Para todas las líneas de Archivo1
while (my $lineas=<DATOS>) {
        chomp($lineas);
        our $col1 = (split "\t",$lineas)[0];
        foreach my $llave (keys %hash){
# Si la primera columna de Archivo1 está entre las claves de Archivo2
                if ($col1 eq $llave) {
#   Escribimos la línea de Archivo1 en el Archivo3
                print OUT "$lineas\n";
                        }
# esta parte es la que no me queda...
                else { print "$elemento"; }
                }
               
}


Lo que quiero agregar es esto último
Perl:
#   Escribimos la línea de Archivo1 en el Archivo3
                print OUT "$lineas\n";
                        }
# esta parte es la que no me queda...
                else { print "$elemento"; }
                }


Ahora quiero que una vez que haya agregado todas las líneas correspondientes del archivo1.txt al archivo3.csv, las líneas que están en el archivo2.txt y que no encontró en archivo1.txt se impriman en el archivo3.txt con el formato:

Código:
AC1100KLP00   0   0


para que quede más o menos así:

Código:
AC1100KLP00   19   51.72
AC1300GEN06   0   0
AC2100GEN05   0   0
AC3030GEN15  7   30.91
AC3030GEN60   0   0
AC4015GEN04   11   4.83
AC4017GEN04   0   4.41
AC4017GEN05   24   5.54
AC5001GEN05   66   6.68


Espero su ayuda, ya estuve dándole vueltas a esto y no he podido completarlo.

De antemano ¡Gracias!
Atte.

Luis G. Mendoza
Mensaje Sab Jul 12, 2008 5:36 pm
explorer
Moderador
Moderador
Registrado: 24 Jul 2005
Mensajes: 3907
Ubicación: Valladolid, España
Responder citando

Enhorabuena. Has conseguido resolver el primer problema.

Lo único, comentarte que los hash se suelen usar para 'recordar' cosas (por algo, también se les llama memoria asociativas). Así que se puede usar de otra forma más inteligente.

Aquí está mi solución.
Perl:
#!/usr/bin/perl
use strict;
use warnings;
use diagnostics;

# Leemos el fichero Archivo2 y almacenamos la primera columna como claves
my %archivo2;

open(FICHERO2, '<Archivo2.txt') or die "$!\n";
while ( my $linea = <FICHERO2> ) {
    my ($columna1) = split(" ", $linea);
    $archivo2{$columna1} = $linea;
}
close(FICHERO2);

# Abrimos los ficheros Archivo1 en lectura y Archivo3 en escritura
open(FICHERO1, '<Archivo1.txt') or die "$!\n";
open(FICHERO3, '>Archivo3.txt') or die "$!\n";

# Para todas las líneas de Archivo1
while ( my $linea = <FICHERO1> ) {

    # Si la primera columna de Archivo1 está entre las claves de Archivo2
    my ($columna1) = split(" ", $linea);
    if ( $archivo2{$columna1} ) {

        # Escribimos la línea de Archivo1 en el Archivo3
        print FICHERO3 $linea;

        # Borramos la clave de Archivo2
        delete $archivo2{$columna1};
    }
}

# Escribimos las líneas de Archivo2 que no se imprimieron
foreach my $clave ( keys %archivo2 ) {
    print FICHERO3 "$clave   0   0\n";
}

# Cerramos los archivos abiertos
close(FICHERO1);
close(FICHERO3);
Mensaje Lun Jul 14, 2008 10:12 am
Lugerius
Perlero Nuevo
Perlero Nuevo
Registrado: 12 Jul 2008
Mensajes: 5
Gracias, es exactamente lo que necesito Responder citando

Gracias, es exactamente lo que necesito, ahora voy a seguir agregando funciones a mi script, la solución que pusiste me despejó varias dudas que tenía con el hash y otras cosas, de todos modos creo que necesito un buen libro de Perl, apenas estoy descubriendo su potencia.

¡Saludos y muchas gracias!

Atte.

Luis G. Mendoza
Publicar nuevo tema   Responder al tema    Foros de discusión -> Básico Todas las horas son GMT - 6 Horas
Página 1 de 1



Powered by phpBB © 2001, 2005 phpBB Group