Página 1 de 1

Agrupar elementos procedentes de diferentes líneas

NotaPublicado: 2013-08-19 11:15 @510
por ptahotep
Hola, tengo un problema, quizás muy básico, pero que no consigo resolver. Y estaba pensando que seguro que existe algún módulo para resolverlo fácilmente.

El problema es el siguiente. Tengo varias líneas con elementos separados por tabuladores:
Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
X       Y       Z       W
X1      Y1      Z1      W1
X2              Z2      W2
X3      Y2      Z3
X2              Z4      W2
X2              Z4      W3
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4


Los ficheros tienen varios megas, pero tienen el formato que muestro en el ejemplo. A veces no se repiten elementos, pero otras veces se repite el mismo elemento de una columna, como ocurre en las últimas filas. Cuando ocurre esto, quisiera agrupar líneas, de la siguiente forma (todo queda igual, excepto que las últimas líneas son unidas a la segunda):
Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
X       Y       Z       W
X1      Y1      Z1      W1
X2              Z4,Z2   W3,W2
X3      Y2      Z3
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4


¿Cómo lo veis? ¿Existe alguna forma fácil de hacerlo sin romperse la cabeza durante horas? Gracias.

Re: Agrupar elementos procedentes de diferentes líneas

NotaPublicado: 2013-08-19 12:33 @564
por explorer
Yo he encontrado una manera, aunque no sé si es muy complicada... consiste en ir leyendo el archivo, e ir guardando la información en una estructura tridimensional ;)
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/perl
  2. use v5.14;
  3. use autodie;
  4.  
  5. my %datos;
  6.  
  7. open my $IN, '<', 'code_35386.txt';
  8.  
  9. my $cabecera = <$IN>;                                   # leemos la cabecera para
  10. my $numero_campos = 1 + ($cabecera =~ tr/\t/\t/);       # saber el número de columnas
  11. #say $numero_campos;
  12.  
  13. #$" = "|";
  14. while (<$IN>) {                                         # leemos el resto de líneas
  15.  
  16.     chomp;
  17.  
  18.     my @campos = split /\t/;
  19.  
  20. #    say "@campos";
  21.  
  22.     for (my $i = 1; $i < $numero_campos; $i++) {     # para todas las columnas posibles
  23.  
  24.         if (not defined $campos[$i]) {               # para el caso de columnas al final de la línea
  25.              $campos[$i] = '';                       # si no están definidas, las ponemos como cadenas vacías
  26.          }
  27.  
  28.         $datos{ $campos[0] }[$i]{$campos[$i]} = 1;   # guardamos la información
  29.     }
  30. }
  31.  
  32. close $IN;
  33.  
  34. #use Data::Dumper;
  35. #say Dumper \%datos;
  36.  
  37. print $cabecera;                                        # salida: sacamos la cabecera original
  38.  
  39. for my $key (sort keys %datos) {                                # para todas las claves encontradas
  40.  
  41.     my @fila = $key;                                            # vamos a construir la nueva línea
  42.  
  43.     for (my $i = 1; $i < $numero_campos; $i++) {                # para todas las columnas posibles
  44.  
  45.         push @fila, join(',', keys %{$datos{$key}[$i]});        # sacamos todos los valores unidos por ','
  46.     }
  47.  
  48.     say join "\t", @fila;                                       # sacamos toda la fila, uniendo las columnas con "\t"
  49. }
Coloreado en 0.003 segundos, usando GeSHi 1.0.8.4
La estructura tridimensional tiene, en su primera dimensión, el valor de la primera columna, que suponemos que debe ser único (agrupar filas). La segunda dimensión es un índice que recorre el resto de columnas. Y la tercera dimensión es un hash, que recuerda qué valores han salido (según el valor de la primera columna y de la columna en que nos encontremos).

El uso de un array para las columnas nos facilita recorrerlas de forma consecutiva. Y el uso de un hash nos sirve tanto para recordar lo que ha salido, como para simplificar los datos repetidos.

El bucle de la 39 a la 49 puede reducirse a esto, aumentando un poco más la velocidad:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. for my $key (sort keys %datos) {                                # para todas las claves encontradas
  2.  
  3.     # sacamos toda la fila, uniendo las columnas con "\t", y cada columna tiene sus valores unidos con ','
  4.     say join "\t", $key, map { join(',', keys %{$datos{$key}[$_]}) } 1 .. $numero_campos-1;
  5. }
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

Re: Agrupar elementos procedentes de diferentes líneas

NotaPublicado: 2013-08-19 12:47 @574
por ptahotep
Muchas gracias, lo probaré a ver qué tal. Lo veo bien, salvo que en la primera columna también suelen repetirse elementos.

Re: Agrupar elementos procedentes de diferentes líneas

NotaPublicado: 2013-08-20 09:59 @458
por explorer
Se supone que el objetivo era ese: agrupar líneas según el valor de la primera columna.