複数の列(長さが異なる)を行に置き換えます。

複数の列(長さが異なる)を行に置き換えます。

誰かが複数の列を行に変換することに関して私と同様の質問をしました。ただし、私が作業している特定の列の形式は少し異なります。私のファイルには以下が含まれているからです。変える時には重複した列番号がある場合があります。

たとえば、

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

この列を次の行に置き換えたいと思います。

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 

次に、次のように、最初の列の値に基づいて行をソートします。

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 

そして、次のように重複行の値を合計します。

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 

100行、400行、700行に重複があるため、対応する列値が合計されたことがわかります。

どんな洞察力や提案でも大変感謝いたします。

ベストアンサー1

私はこれにPerlの短絡モードを使います:

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

次のように使用してください。

$ /path/to/script input_file > output_file

このコードはテストされ、正常に動作します。 @cjmがコメントで指摘したように、入力ファイルが大きい場合は時間がかかることがあります。最も時間がかかる可能性が最も高いステップが最後のsort鍵です。

おすすめ記事