我有一个制表符分隔的文件(带标题行),其中我想根据另一列中数据的存在来计算某些值的总和。
这就是我的表格:
C1 C2 C3 C4
a x e 1
b x 3
c y 1
d z f 4
对于C2中的所有相同值,我想在C3中得到相应值的总和。 所以新表应如下所示:
C1 C2 C3 C4 C5
a x e 1 4
b x 3 4
c y 1 1
d z f 4 4
所以我想保留我的表的原始结构(列C1,C2,C3,C4和相同的行数),但最后我想添加另一列,在这种情况下,对于行a和b将C4中的值相加并放入C5中,因为C2的值是相同的。线c和C的C5值与C4相同,因为C2中的y和z是唯一的。
任何人都可以帮我在Perl中执行此操作吗?我想我应该循环遍历文件并创建一个变量$ sum,通过遍历每一行,他将C4的数量相加,然后放入C5。
答案 0 :(得分:5)
逐行读取数据文件,将每一行推送到一个数组,并使用第2列作为键将第4列的值记录在哈希中。完成后,迭代该数组,逐个打印其元素和相应的第4列。
#!/usr/bin/perl
use strict;
use warnings;
my $header = <DATA>;
chomp $header;
$header = join "\t", (split /\t/, $header), 'C5';
my (%record, @lines);
while (<DATA>) {
chomp;
my @cols = split /\t/;
$record{$cols[1]} += $cols[3];
push @lines, \@cols;
}
print "$header\n";
foreach (@lines) {
print (join "\t", (@$_, $record{$_->[1]}), "\n");
}
__DATA__
C1 C2 C3 C4
a x e 1
b x 3
c y 1
d z f 4
答案 1 :(得分:1)
perl -lane'
BEGIN { $, ="\t" }
print(@F, "C4"),next if $. ==1;
$s{ $F[1] } += $F[2];
push @r, [ @F ];
END {
print @$_, $s{$_->[1]} for @r;
}
' file
输出
C1 C2 C3 C4
a x 1 4
b x 3 4
c y 1 1
d z 4 4
脚本版本,
use strict;
use warnings;
local $, ="\t";
local $\ = "\n";
my %s;
my @r;
while (<>) {
chomp;
my @F = split;
print(@F, "C4"),next if $. ==1;
$s{ $F[1] } += $F[2];
push @r, [ @F ];
}
print @$_, $s{$_->[1]} for @r;
答案 2 :(得分:0)
一个简单的解决方案是将C3中的值放入数组中,然后将每行的内容打印到C3。 对于C4的第i列,将array [i-1]的内容与array [i]和array [i + 1]的数据进行比较,然后将特定行的数组值与之前的数组进行比较。下一行。如果它们相等,则添加它们,打印它们并移动到下一行。
对于C3等于2个连续值的情况,这可以很容易地改变。
答案 3 :(得分:0)
如果您不介意两次阅读文件,也可以使用awk
轻松实现这一目标:
$ awk -v OFS='\t' 'NR==FNR{a[$2]+=$3;next}{print $1,$2,$3,$2=="C2"?"C4":a[$2]}' t.txt t.txt
C1 C2 C3 C4
a x 1 4
b x 3 4
c y 1 1
d z 4 4
如果您不介意手动修复列标题,请填写以下内容:
$ awk -v OFS='\t' 'NR==FNR{a[$2]+=$3;next}{print $1,$2,$3,a[$2]}' t.txt t.txt
C1 C2 C3 0
a x 1 4
b x 3 4
c y 1 1
d z 4 4