2010-07-14 12 views
13

Ho iniziato a imparare perl e mi piace provare nuove cose.Transpose in perl

Ho qualche problema nell'elaborazione del testo. ho qualche testo del modulo,

0 1 2 3 4 5 6 7 8 9 10 

6 7 3 6 9 3 1 5 2 4 6 

voglio trasporre questo testo. Ad esempio, voglio creare righe come colonne e colonne come righe. Id c'è un modo per farlo in perl?

Grazie a tutti.

+0

Grazie per la modifica. :) Fammi sapere come inserire dati importanti all'interno di quel blocco. Mi prenderò cura di esso dalla prossima volta :) – jerrygo

+0

Rientra ogni riga di 4 spazi. –

+0

Immagino che il vero modo perl sarebbe utilizzare un modulo CPAN, come [Data :: Pivot] (http://search.cpan.org/~bdulfer/Data-Pivot-0.05/Pivot.pm), ma probabilmente è questo non è la sfida che cercavi ... – Mike

risposta

12

Quindi questa soluzione utilizza un array di array, ogni array nidificato è una riga di dati. Molto semplicemente si esegue il ciclo sulle colonne in ciascuna riga e le si inserisce su un altro array di array utilizzando l'indice della colonna come indice su cui inserire il valore. Questo ha l'effetto di ruotare i dati come richiesto.

#!/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"; 
} 

Questo si traduce in:

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

Grazie. Ottima soluzione :) – jerrygo

+0

Non è necessario premere per l'inizializzazione: '@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

È vero, non è necessario. Ma come tutto il resto in Perl c'è più di un modo per farlo. :) – dalton

3

C'è sicuramente, e Mike ha indicato il modo più semplice. Se stai imparando, probabilmente vuoi scrivere la tua funzione?
In primo luogo, si vuole split ogni riga su spazi per ottenere un array di valori (o push la list of words nella matrice, come in Dalton's answer, in Perl, c'è sempre più di un modo per fare qualcosa)
Poi, for each element in the array, vuoi stamparlo e la sua controparte nel secondo array sulla stessa linea. (Cosa farai se un array finisce prima dell'altro?)

Ovviamente, se vuoi imparare Perl, vorrai anche imparare ad usare anche CPAN, quindi vale ancora la pena provare a usare Data ::Perno.

+0

Grazie per i vostri suggerimenti. Ci proverei senz'altro. – jerrygo

5

Ecco uno schema di un modo per trasporre i dati. Lavorare attraverso questo esempio sarà istruttivo perché dovrai usare CPAN, imparerai a conoscere i moduli utili List::Util e List::MoreUtils, imparerai le basi delle strutture di dati complesse (vedi perlreftut, perldsc e perllol), e arriverete a usa un iteratore in 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

Grazie. Proverei tutti quelli :) – 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

Ecco il mio nuovo script di trasporre un file delimitato da tabulazioni. Cambia \ t al tuo delimitatore, se lo desideri.

#!/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 come un carattere 104 "un liner" (con apostrofo-backslash-newline apostrofo aggiunta per evitare lo scorrimento orizzontale):

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]}]; 

array deve essere una matrice, cioè le colonne devono essere uguali per ogni riga, array originale viene distrutto

questo codice non userà supplementare memoria per transpose, x2 per altre librerie, per array di grandi dimensioni ad esempio 100x1M, è importante