每组总和不同的值

时间:2014-04-28 13:03:06

标签: perl

我有一个制表符分隔的文件(带标题行),其中我想根据另一列中数据的存在来计算某些值的总和。

这就是我的表格:

 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。

4 个答案:

答案 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