我有几百行格式的文件
1st 2n 2p 3n 3p 4n 4p
1ABJa 2 20 8 40 3 45
1ABJb 2 40 8 80 3 45
2C3Da 4 50 5 39 2 90
2D4Da 1 10 8 90 8 65
(制表符分隔文件)
从这个文件中,我想操纵第一列中具有类似4个开头字符的所有行(即1ABJa和1ABJb)并执行:
2n, 3n, 4n...
,数字将相加; 2p, 3p, 4p, ...
,数字将被平均。(请注意,这可以通过列位置而不是名称来指定)。 然后这会产生:
1st 2n 2p 3n 3p 4n 4p
1ABJab 4 30 16 60 6 45
2C3Da 4 50 5 39 2 90
2D4Da 1 10 8 90 8 65
你会如何解决这个问题?
这可能是执行此操作最复杂的方法,但这里有:我正在考虑创建第1列的所有4个字符的唯一元素的数组。然后,对于该数组,运行一个循环,找到与这4个字符匹配的所有实例。如果有多个实例,请识别它们,推送列并操纵它们。这是我到现在为止的观点:
#!/usr/local/bin/perl
use strict;
use warnings;
use feature 'say';
use List::MoreUtils qw(uniq);
my $dir='My\\Path\\To\\Directory';
open my $in,"<", "$dir\\my file.txt" or die;
my @uniqarray; my @lines;
#collects unique elements in 1st column and changes them to 4-character words
while (my $line = <$in>) {
chomp $line;
@lines= split '\t', $line;
if (!grep /$lines[0]/, @uniqarray ){
$lines[0] =~ s/^(.{4}).*/$1/;
push @uniqarray,$lines[0];
}
}
my @l;
#for @uniqarray, find all rows in the input that match them. if more than 1 row is found, manipulate the columns
while (my $something=<$in>) {
chomp $something;
@l= split '\t', $something;
if ( map $something =~ m/$_/,@uniqarray){
**[DO STUFF]**
}
}
print join "\n", uniq(@uniqarray);
close $in;
答案 0 :(得分:2)
怎么样:
my $result;
my $head = <DATA>;
while(<DATA>) {
chomp;
my @l = split/\s+/;
my ($k1,$k2) = ($l[0] =~ /^(....)(.*)$/);
$result->{$k1}{more} .= $k2 // '';
$result->{$k1}{nbr}++;
;
$result->{$k1}{n}{2} += $l[1];
$result->{$k1}{n}{3} += $l[3];
$result->{$k1}{n}{4} += $l[5];
$result->{$k1}{p}{2} += $l[2];
$result->{$k1}{p}{3} += $l[4];
$result->{$k1}{p}{4} += $l[6];
}
print $head;
foreach my $k (keys %$result) {
print $k,$result->{$k}{more},"\t";
for my $c (2,3,4) {
printf("%d\t",$result->{$k}{n}{$c});
if (exists($result->{$k}{nbr}) && $result->{$k}{nbr} != 0) {
printf("%d\t",$result->{$k}{p}{$c}/$result->{$k}{nbr});
} else {
printf("%d\t",0);
}
}
print "\n";
}
<强>输出:强>
1st 2n 2p 3n 3p 4n 4p
2D4Da 1 10 8 90 8 65
1ABJab 4 30 16 60 6 45
2C3Da 4 50 5 39 2 90
答案 1 :(得分:1)
这似乎可以满足您的需求。它为每个不同的四字符前缀保留一组哈希数据:一个在密钥n
下具有相同前缀的记录数,一个数组,用于保存密钥{{下的该前缀的列总数1}},以及包含在密钥totals
下为该前缀看到的所有后缀的哈希。
在第一次看到前缀时,会将前缀添加到数组suffixes
中,以便输出的输出顺序与输入的顺序相同。
将@prefixes
数组的所有偶数列除以totals
之后,只需累积数据然后以所需格式转储数据。
n
<强>输出强>
use strict;
use warnings;
open my $fh, '<', 'data.txt' or die $!;
print scalar <$fh>; # Copy header
my %data;
my @prefixes;
while (<$fh>) {
chomp;
my @fields = split /\t/;
my ($prefix, $suffix) = shift(@fields) =~ /(.{4})(.*)/;
push @prefixes, $prefix unless $data{$prefix};
++$data{$prefix}{n};
++$data{$prefix}{suffixes}{$suffix};
$data{$prefix}{totals}[$_] += $fields[$_] for 0 .. $#fields;
}
for my $prefix (@prefixes) {
my $val = $data{$prefix};
my $totals = $val->{totals};
for (my $i = 1; $i < @$totals; $i += 2) {
$totals->[$i] /= $val->{n};
}
my $suffixes = join '', sort keys %{ $val->{suffixes} };
print join("\t", "$prefix$suffixes", @$totals), "\n";
}