有人问了与我类似的问题,涉及将多列转为行。但是,我正在处理的特定列格式略有不同,因为我的文件包含变化的有时有重复项的列数。
例如:
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
键。