Transpor várias colunas (de comprimentos variados) em linhas

2

Uma pergunta semelhante à minha foi solicitada que envolvia a transposição de várias colunas em linhas. No entanto, o formato de coluna específico com o qual estou lidando é um pouco diferente, pois meu arquivo contém um número de colunas variando que às vezes tem duplicatas.

Por exemplo:

100  
1  
2
3  

200  300  
1    1  
2    2
3    3

100  
1  
2  
3

400  500  600  700  800  900  
1    1    1    1    1    1
2    2    2    2    2    2
3    3    3    3    3    3

100 400 700   
1   1   1
2   2   2
3   3   3

Gostaria de transpor essas colunas para linhas semelhantes às seguintes:

100 1 2 3
200 1 2 3
300 1 2 3
100 1 2 3
400 1 2 3
500 1 2 3
600 1 2 3
700 1 2 3
800 1 2 3
900 1 2 3
100 1 2 3
400 1 2 3
700 1 2 3 

E, em seguida, classifique as linhas pelos valores da primeira coluna da seguinte forma:

100 1 2 3
100 1 2 3
100 1 2 3    
200 1 2 3
300 1 2 3
400 1 2 3
400 1 2 3    
500 1 2 3
600 1 2 3
700 1 2 3
700 1 2 3    
800 1 2 3
900 1 2 3 

E some os valores das linhas duplicadas da seguinte forma:

100 3 6 9    
200 1 2 3
300 1 2 3
400 2 4 6
500 1 2 3
600 1 2 3
700 2 4 6   
800 1 2 3
900 1 2 3 

Você notará que, como as linhas 100, 400 e 700 tinham duplicatas, seus valores colunares foram somados.

Qualquer ideia ou sugestão é muito apreciada.

    
por Dave 21.11.2013 / 00:00

1 resposta

3

Eu usaria o modo de parágrafo do Perl para isso:

#!/usr/bin/env perl

use strict;
use warnings;

my %final_lines;        # Data structure to hold the modified lines
my $filename = shift // die "No input file given!\n";
open my $IN,'<',$filename or die "Failed to open $filename for input: $!\n";

PARAGRAPH: {
    local $/="";        # Paragraph mode
    while(<$IN>){       # Read a new "paragraph"
        my @lines  = split /\n/;
        my @fields = split /\s+/,(shift @lines);
        my $line_number =0;
        for my $line (@lines){
            my @data = split /\s+/,$line;
            map { 
                  $final_lines{$fields[$_]}->[$line_number] += $data[$_]
            } (0..$#data);
            $line_number++;
        }
    }
}

for my $key (sort { $a <=> $b } keys %final_lines){
    local $,=' ';
    print STDOUT $key,@{$final_lines{$key}};
    print STDOUT "\n";
}

Use assim:

$ /path/to/script input_file > output_file

Este código é testado e deve funcionar bem. Como apontado por @cjm nos comentários, provavelmente levará algum tempo se o seu arquivo de entrada for grande. A etapa com maior probabilidade de levar tempo é o sort final das chaves.

    
por 21.11.2013 / 11:12

Tags