• Publicidad

Comparar columnas

¿Apenas comienzas con Perl? En este foro podrás encontrar y hacer preguntas básicas de Perl con respuestas aptas a tu nivel.

Comparar columnas

Notapor carolina_2 » 2017-09-10 20:26 @893

Hola, soy nueva en Perl y quería saber si me pueden ayudar.

Tengo dos archivos y tengo que buscar coincidencias entre ambos en las columnas correspondientes a año, mes, día y hora, y luego si hay coincidencias entre ellos me imprima en un tercer archivo algunas columnas de esas líneas y si no existen similitudes me imprima los datos en un cuarto archivo.

Mi problema es que si las fechas y horas no están ubicadas en la misma posición de linea en ambos archivos el programa considera como que no hay coincidencias.

Mi programa es el que sigue
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. open( f1, "<dato_1.dat" ) || die "can not open file";
  2. open( f2, "<dato_2.csv" ) || die "can not open file";
  3. my (@datos)   = <f1>;
  4. my (@datos_2) = <f2>;
  5. my ($valores);
  6. my ($valores_2);
  7. open my $OUT_1, '>', 'datos-interes.dat' or die $!;
  8. open my $OUT_2, '>', 'sobran.dat'        or die $!;
  9. while (@datos) {
  10.     $valores   = shift @datos;
  11.     $valores_2 = shift @datos_2;
  12.     chomp $valores;
  13.     @data = split( ",", $valores );
  14.     chomp $valores_2;
  15.     @data_2 = split( ",", $valores_2 );
  16.     if ( @data[0] == @data_2[0] and @data[1] == @data_2[1] and @data[2] == @data_2[2] and @data[3] == @data_2[3] ) {
  17.         print {$OUT_1}
  18.             "$data[0],$data[1],$data[2],@data[3],@data_2[0],$data_2[1],$data_2[2],$data_2[3],$data[4],$data[5],$data[6],$data[7],$data[8],$data_2[4],$data_2[5],$data_2[6],$data_2[7],$data_2[8]\n";
  19.     }
  20.     else {
  21.         print {$OUT_2}
  22.             "$data[0],$data[1],$data[2],@data[3],@data_2[0],$data_2[1],$data_2[2],$data_2[3],$data[4],$data[5],$data[6],$data[7],$data[8],$data_2[4],$data_2[5],$data_2[6],$data_2[7],$data_2[8]\n";
  23.     }
  24. }
  25. close $OUT;
  26.  
Coloreado en 0.003 segundos, usando GeSHi 1.0.8.4
Adjuntos
datos_2.csv
archivo f2
(901 Bytes) 142 veces
datos_1.csv
archivo f1
(901 Bytes) 141 veces
Última edición por explorer el 2017-09-10 22:14 @968, editado 1 vez en total
Razón: Marcas para código Perl
carolina_2
Perlero nuevo
Perlero nuevo
 
Mensajes: 4
Registrado: 2017-09-10 18:54 @829

Publicidad

Re: Comparar columnas

Notapor explorer » 2017-09-11 06:04 @295

Bienvenida a los foros de Perl en Español, carolina_2.

Lo que deberías hacer es comparar cada entrada del primer archivo con todas las entradas del segundo. Algo así como un doble bucle, anidados. Si coinciden las fechas de uno con el otro, tienes una coincidencia. Y si al final de repasar el segundo archivo no hay coincidencias, no tenemos ninguna coincidencia.

Una solución mejor es usar un par de hashes en Perl, para hacer la búsqueda más rápida y eficiente.

Por estos foros ya hemos comentado problemas parecidos:
Inténtalo, y si te atascas, vuelve por aquí y te damos más pistas.
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14476
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Comparar columnas

Notapor carolina_2 » 2017-09-22 14:55 @663

Hola.

He tratado de realizar el programa en el poco tiempo disponible que he tenido y no me ha dado resultado: me salta un error. Si me pueden indicar lo que hago mal sería genial. Aquí está lo que traté de realizar:

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/env perl
  2. use warnings;
  3. use strict;
  4.  
  5. my @columnas;
  6. my @columnas_b;
  7. my %hash_1;
  8. my %hash_2;
  9. open my $IN, '<', 'archivo1.csv' or die "can not open file";
  10. my @lines = <$IN>;
  11. close $IN;
  12. for my $line (@lines) {
  13.     chomp $line;
  14.     my @columnas = split( ",", $line );
  15.     while ( my ( $i, $v ) = each @columnas ) {
  16.         $columnas[$i] .= $v;
  17.     }
  18. }
  19. my @dia = @columnas[2];
  20. %hash_1{@dia} = ( @columnas[0], @columnas[1], @columnas[3], @columnas[4], @columa[5] );
  21. @keys = keys(%hash_1);
  22. close $IN;
  23.  
  24. open my $IN_2, '<', 'archivo2.csv' or die "can not open file";
  25. while ( my $linea = <$IN_2> ) {
  26.     chomp $linea;
  27.     my @columnas_b = split( ",", $linea );
  28.     while ( my ( $j, $k ) = each @columnas_b ) {
  29.         $columnas_b[$j] .= $k;
  30.     }
  31. }
  32. my @dia_2 = @columnas_b[2];
  33. %hash_2{@dia_2} = ( @columnas_b[0], @columnas_b[1], @columnas_b[3], @columnas_b[4], @columa_b[5] );
  34. @keys_2 = keys(%hash_2);
  35. close $IN_2;
  36.  
  37. open my $OUT,   '>', 'interes.dat' or die $!;
  38. open my $OUT_2, '>', 'sobran.dat'  or die $!;
  39.  
  40. foreach my %keys{ %hash (@dia) }{
  41.     if ( @dia = @dia_2 ) {
  42.         print {$OUT} %hash_1{@dia}, %hash_2{@dia_2};
  43.     }
  44.     } else { print {$OUT} %hash_1{@dia}, %hash_2{@dia_2} }
  45. }
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4
carolina_2
Perlero nuevo
Perlero nuevo
 
Mensajes: 4
Registrado: 2017-09-10 18:54 @829

Re: Comparar columnas

Notapor explorer » 2017-09-22 19:03 @836

Con la adición de

use strict;
use warnings;

el propio Perl nos dice qué está mal (al menos, a nivel sintáctico):
Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
Global symbol "@columa" requires explicit package name (did you forget to declare "my @columa"?) at ./compara_columnas.pl line 23.
Global symbol "@keys" requires explicit package name (did you forget to declare "my @keys"?) at ./compara_columnas.pl line 24.
Global symbol "@columa_b" requires explicit package name (did you forget to declare "my @columa_b"?) at ./compara_columnas.pl line 36.
Global symbol "@keys_2" requires explicit package name (did you forget to declare "my @keys_2"?) at ./compara_columnas.pl line 37.                  
Missing $ on loop variable at ./compara_columnas.pl line 43.
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4

Ahí ya te está marcando una serie de líneas con variables que no sabe de dónde salen. Por ejemplo, en la línea 23 se hace referencia a una variable llamada @columa, que no se declara ni se usa en ningún lado.

Aparte de estos errores sintácticos, hay otros más:
  • En la línea 25 cierras $IN, pero en realidad ya lo habías cerrado en la línea 12.
  • En las líneas 17 y 31 se hace uso de each() sobre un array... algo que solo está permitido desde Perl v5.12 (deberías poner un 'use v5.12;' al principio del programa.
  • En la línea 45 estás haciendo una asignación, no una comparación. ¿Es eso lo que realmente quieres hacer?
  • En la línea 42 abres un archivo asignado a $OUT_2, pero luego no escribes nada en él.
  • No creo que las líneas 22 y 36 estén bien... extraes UN valor de @columnas y lo guardas en @dia, y luego usas ese mismo valor para crear una entrada en el hash %hash_1, pero en realidad guardas cinco valores, con lo que estás creando dos entradas en el hash... ¡puff, qué lío!
  • No veo la comparación de año, mes, día y hora, o ver cómo se crea una entrada en un hash para ese momento.
  • Los datos que guardas son los que tienen el índice 0, 1, 3, 4 y 5, es decir: año, mes, hora, Pedidos y Dato 1. ¿Eso es correcto? ¿Dejar al día fuera? ¿Y dejar el resto de columnas fuera? En la descripción del problema dices que si hay coincidencias de año, mes, día y hora, se deben imprimir "algunas columnas", pero no sabemos cuáles son.
Hay algunas cosas que no sabemos.

Si hay coincidencias de año, mes, día y hora entre los dos archivos, ¿qué es lo que debe salir? ¿las columnas de los dos archivos o solo del segundo? Y lo mismo para el caso de no haber coincidencia: ¿deben salir hacia el cuarto archivo las columnas del primer archivo, los del segundo, o de los dos?

Esta es una posible solución, pero depende de las dudas que tenemos ahora.
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/env perl
  2. use v5.14;
  3. use utf8;
  4. use strict;
  5. use warnings;
  6. use autodie;
  7.  
  8. my $archivo1_nombre = 'datos_1.csv';
  9. my $archivo2_nombre = 'datos_2.csv';
  10. $; = ',';                                                       # separador de dimensiones en hashes
  11.  
  12. my %archivos;
  13.  
  14. ## Leemos el primer archivo
  15. open my $IN, '<', $archivo1_nombre;
  16. my $cabecera = <$IN>;                                           # leemos la primera línea
  17. while (<$IN>) {
  18.         chomp;
  19.         my ($año, $mes, $día, $hora, @datos) = split /[,]/;
  20.  
  21.         push @{ $archivos{$año, $mes, $día, $hora} }, join(',', @datos);
  22. }
  23. close $IN;
  24.  
  25. ## Leemos el segundo archivo
  26. open my $IN2, '<', $archivo2_nombre;
  27. $cabecera = <$IN2>;                                             # leemos la primera línea
  28. while (<$IN2>) {
  29.         chomp;
  30.         my ($año, $mes, $día, $hora, @datos) = split /[,]/;
  31.  
  32.         push @{ $archivos{$año, $mes, $día, $hora} }, join(',', @datos);
  33.  
  34. }
  35. close $IN2;
  36.  
  37. #use Data::Dumper;
  38. #say Dumper \%archivos;                 # comprobación
  39.  
  40. ## Resultado
  41. #
  42. # Recorremos el hash multidimensional, y vemos cuántas coincidencias hay.
  43. # Si solo hay una, lo guardamos en sobran.csv
  44. # Si hay más de una, lo guardamos en interes.csv
  45. open my $INTERES, '>', 'interes.csv';
  46. open my $SOBRAN,  '>', 'sobran.csv';
  47.  
  48. print $INTERES $cabecera;
  49. print $SOBRAN  $cabecera;
  50.  
  51. for my $fecha (keys %archivos) {                                # para todas las fechas
  52.  
  53.         my @registros         = @{ $archivos{$fecha} };         # entradas para esa fecha
  54.  
  55.         my $OUT = @registros > 1 ? $INTERES : $SOBRAN;          # según el número de entradas, escogemos canal de salida
  56.  
  57.         for my $datos ( @registros ) {                          # para todos los @registros
  58.  
  59.                 say $OUT "$fecha,$datos";                       # sacamos $fecha y @datos
  60.         }
  61. }
  62.  
  63. close $INTERES;
  64. close $SOBRAN;
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14476
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Comparar columnas

Notapor carolina_2 » 2017-09-23 08:57 @414

:D los datos de ambos archivos tienen que salir juntos, en la misma linea
saludos
carolina_2
Perlero nuevo
Perlero nuevo
 
Mensajes: 4
Registrado: 2017-09-10 18:54 @829

Re: Comparar columnas

Notapor explorer » 2017-09-24 07:38 @359

¿Puedes poner un ejemplo? ¿Separados por una columna o por comas?

Sería interesante ver el resultado que debería dar dados los dos archivos que adjuntaste al inicio.
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14476
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Comparar columnas

Notapor carolina_2 » 2017-09-24 10:57 @498

Lo que debería obtener serían los datos correspondientes a las fechas coincidentes de ambos archivos separados por comas en una misma línea. Con los encabezados correspondientes a los datos:

Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
ano,mes,dia,hora,Pedidos,Dato1,Dato2,Dato3,Dato4,ano,mes,dia,hora,Pedidos (del archivo datos_2),Dato1(del archivo datos_2),Dato2(del archivo datos_2),Dato3(del archivo datos_2),Dato4(del archivo datos_2)
2012,5,6,7,11,75,53,44,18,2012,5,6,7,11,33,53,44,1234
2012,5,7,6,13,87,63,51,8,2012,5,7,6,13,87,63,51,8
2012,5,8,8,14,100,66,47,14,2012,5,8,8,14,100,66,47,14
2012,5,9,7,13,100,86,72,26,2012,5,9,7,13,100,86,72,26
2012,5,10,6,16,100,82,68,19,2012,5,10,6,16,100,82,68,19
2013,5,11,24,16,100,81,52,23,2013,5,11,24,16,100,81,52,23
2013,5,12,24,15,100,72,48,13,2013,5,12,24,15,100,72,48,13
2013,6,13,24,21,100,56,33,3,2013,6,13,24,21,100,56,33,3
2014,7,19,5,19,94,61,37,13,2014,7,19,5,19,94,61,37,13
2014,7,20,11,20,57,43,30,13,2014,7,20,11,20,57,43,30,13
2014,7,21,12,21,57,44,33,5,2014,7,21,12,21,57,44,33,5
2014,7,22,3,20,48,40,33,8,2014,7,22,3,20,48,40,33,8
2014,7,23,5,21,76,54,38,6,2014,7,23,5,21,76,54,38,6
2014,7,24,11,22,81,53,40,3,2014,7,24,11,22,81,53,40,3
2013,7,25,12,20,67,60,52,11,2013,7,25,12,20,67,60,52,11
2015,7,26,3,20,88,75,63,6,2015,7,26,3,20,88,75,63,6
2015,7,27,2,14,93,51,35,10,2015,7,27,2,14,93,51,35,10
2013,6,14,23,26,71,48,36,6,2013,6,14,23,26,71,48,36,6
2013,6,15,23,23,68,57,53,6,2013,6,15,23,23,68,57,53,6
2013,6,16,23,24,100,60,38,3,2013,6,16,23,24,100,60,38,3
2013,6,17,23,27,94,54,36,5,2013,6,17,23,27,94,54,36,5
2014,6,18,5,26,88,53,29,6,2014,6,18,5,26,88,53,29,6
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4
carolina_2
Perlero nuevo
Perlero nuevo
 
Mensajes: 4
Registrado: 2017-09-10 18:54 @829

Re: Comparar columnas

Notapor explorer » 2017-09-24 12:05 @545

Bueno, en ese caso se puede simplificar bastante.
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/env perl
  2. use v5.14;
  3. use utf8;
  4. use strict;
  5. use warnings;
  6. use autodie;
  7.  
  8. my $archivo1_nombre = 'datos_1.csv';
  9. my $archivo2_nombre = 'datos_2.csv';
  10. $; = ',';                                                       # separador de dimensiones en hashes
  11.  
  12. my %archivo1;
  13.  
  14.  
  15. ## Leemos el primer archivo
  16. open my $IN, '<', $archivo1_nombre;
  17.  
  18. my $cabecera1 = <$IN>;                                          # leemos la primera línea
  19. chomp $cabecera1;
  20.  
  21. while (my $línea = <$IN>) {
  22.         chomp $línea;
  23.         my ($año, $mes, $día, $hora, @datos) = split /[,]/, $línea;
  24.  
  25.         $archivo1{$año, $mes, $día, $hora} = $línea;         # guardamos los @datos asociados a la fecha
  26. }
  27.  
  28. close $IN;
  29.  
  30.  
  31. ## Leemos el segundo archivo, procesando cada línea
  32. open my $IN2, '<', $archivo2_nombre;
  33.  
  34. my $cabecera2 = <$IN2>;                                         # leemos la primera línea
  35. chomp $cabecera2;
  36.  
  37. ## Archivos de salida
  38. open my $INTERES, '>', 'interes.csv';
  39. open my $SOBRAN,  '>', 'sobran.csv';
  40.  
  41. say $INTERES "$cabecera1,$cabecera2";
  42. say $SOBRAN   $cabecera2;
  43.  
  44.  
  45. while (my $línea = <$IN2>) {                                   # para todas las líneas
  46.         chomp $línea;
  47.         my ($año, $mes, $día, $hora, @datos) = split /[,]/, $línea;
  48.  
  49.         if (exists $archivo1{$año, $mes, $día, $hora}) {              # coincidencia de fecha
  50.             say $INTERES "$archivo1{$año, $mes, $día, $hora},$línea";
  51.         }
  52.         else {                                                          # no coincidencia
  53.             say $SOBRAN  $línea;
  54.         }
  55. }
  56. close $IN2;
  57.  
  58. close $INTERES;
  59. close $SOBRAN;
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14476
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España


Volver a Básico

¿Quién está conectado?

Usuarios navegando por este Foro: No hay usuarios registrados visitando el Foro y 9 invitados

cron