2010-07-14 9 views
13

Comencé a aprender perl y me gusta probar cosas nuevas.Transponer en perl

Tengo algún problema en el procesamiento de texto. tengo algo de texto del formulario,

0 1 2 3 4 5 6 7 8 9 10 

6 7 3 6 9 3 1 5 2 4 6 

Quiero incorporar la presente texto. Al igual que, quiero hacer filas como columnas y columnas como filas. ¿Hay alguna manera de hacer esto en perl?

Gracias a todos.

+0

Gracias por la edición. :) Déjame saber cómo colocar datos importantes dentro de ese bloque. Me ocuparé de ello la próxima vez :) – jerrygo

+0

Sangrar cada línea por 4 espacios. –

+0

Supongo que la verdadera manera de Perl sería utilizar un módulo de CPAN, como [Datos :: Pivote] (http://search.cpan.org/~bdulfer/Data-Pivot-0.05/Pivot.pm), pero eso es probablemente no es el desafío que buscabas ... – Mike

Respuesta

12

Así que esta solución usa una matriz de matrices, cada matriz anidada es una fila de datos. Muy simplemente, recorre las columnas de cada fila y las inserta en otra matriz de matrices utilizando el índice de la columna como el índice sobre el que desea insertar el valor. Esto tiene el efecto de pivotar los datos como usted solicitó.

#!/usr/bin/env perl 

my @rows =(); 
my @transposed =(); 

# This is each row in your table 
push(@rows, [qw(0 1 2 3 4 5 6 7 8 9 10)]); 
push(@rows, [qw(6 7 3 6 9 3 1 5 2 4 6)]); 

for my $row (@rows) { 
    for my $column (0 .. $#{$row}) { 
    push(@{$transposed[$column]}, $row->[$column]); 
    } 
} 

for my $new_row (@transposed) { 
    for my $new_col (@{$new_row}) { 
     print $new_col, " "; 
    } 
    print "\n"; 
} 

Esto resulta en:

0 6 
1 7 
2 3 
3 6 
4 9 
5 3 
6 1 
7 5 
8 2 
9 4 
10 6 
+0

Gracias. Gran solución :) – jerrygo

+0

No necesita presionar para la inicialización: '@rows = ([qw (0 1 2 3 4 5 6 7 8 9 10)], [qw (6 7 3 6 9 3 1 5 2 4 6) ]); ' – dolmen

+0

Eso es cierto, no es necesario. Pero como todo lo demás en Perl, hay más de una forma de hacerlo. :) – dalton

3

Sin duda lo hay, y Mike ha señalado la forma más sencilla. Si estás aprendiendo, ¿es probable que quieras escribir tu propia función?
En primer lugar, que desea split cada línea de espacios para conseguir una matriz de valores (o push la list of words en la matriz, como en Dalton's answer; en Perl, siempre hay más de una manera de hacer cualquier cosa)
Entonces, for each element in the array, desea imprimirlo y su contraparte en la segunda matriz en la misma línea. (¿Qué harás si una matriz se agota antes que la otra?)

Por supuesto, si quieres aprender Perl, definitivamente también querrás aprender a usar CPAN, así que todavía vale la pena intentarlo. ::Pivote.

+0

Gracias por sus sugerencias. Definitivamente probaría esos. – jerrygo

5

He aquí un bosquejo de una manera de incorporar los datos. Trabajando con este ejemplo será instructivo porque necesitará usar CPAN, aprenderá sobre los útiles módulos List::Util y List::MoreUtils, aprenderá los conceptos básicos de estructuras de datos complejos (consulte perlreftut, perldsc y perllol), y obtendrá usa un iterador en Perl.

use strict; 
use warnings; 
use List::MoreUtils qw(each_arrayref); 

my @raw_data = (
    '0 1 2 3 4 5 6 7 8 9 10', 
    '6 7 3 6 9 3 1 5 2 4 6', 
); 

my @rows = ... ; # Look up map() and split() to fill in the rest. 
       # You want an array of arrays. 

my @transposed; # You will build this in the loop below. 

my $iter = each_arrayref(@rows); # See List::MoreUtils documentation. 

while (my @tuple = $iter->()){ 
    # Do stuff here to build up @transposed, which 
    # will also be an array of arrays. 
} 
+0

Gracias. Intentaría todos aquellos :) – jerrygo

1
use strict; 
# read the first line 
my @labels = split ' ', <>; 
# read and ignore the empty second line 
<>; 
# read the third line 
my @values = split ' ', <>; 
# transpose (I suppose you'll do more with the table than just printing it) 
my %table = map { $labels[$_] => $values[$_] } 0..$#labels; 
# print 
foreach (@labels) { 
    print "$_ $table{$_}\n"; 
} 
2

Aquí está mi nuevo guión para transponer un archivo delimitado por tabuladores. Cambie \ t a su delimitador si lo desea.

#!/usr/bin/perl -anF/\t|\n/ 
$n = @F - 1 if !$n; 
for $i (0..$n) { 
    push @{ $m->[$i] }, $F[$i]; 
} 
END { 
    for $r (@$m) { 
     print join("\t", @$r), "\n"; 
    } 
} 

o como un carácter 104 "un trazador de líneas" (con apóstrofo-backslash-salto de línea-apóstrofe añadido para evitar el desplazamiento horizontal):

perl -anF'\t|\n' -e'[email protected]!$n;for(0..$n){[email protected]{$$m[$_]},$F[$_]}'\ 
'END{print map{join"\t",@$_,"\n"}@$m}' 
0
use strict; 
my ($i, $rows, $cols) = (0, 10, 100); 
# initiate array 10x100 
my $array = [map {[map {$i++} (1..$cols)]} (1..$rows)]; 
# transpose array into 100x10 array 
my $transpose = [map {[map {shift @$_} @$array]} @{$array->[0]}]; 

matriz debe ser una matriz, es decir, columnas debe ser igual para cada fila, matriz original será destruido

este código no utilizará adicional memoria para transponer, x2 para otras bibliotecas, para matriz grande por ejemplo 100x1M, importa