我正在编写一个脚本,其中我使用了一个文本文件,其中一列中可以有两个字母(A,B,C或D),由"和&分隔开来。 #34 ;.此列也可以只包含其中一个字母。我必须在脚本的其余部分使用这两个字母进行进一步的计算。这是我的输入文件(此处为$variants
)的简化示例:
C1 C2 C3 C4 C5 C6 ... C9
text 2 A D values and text in the other columns
text 4 B C values and text in the other columns
text 5 A B,D values and text in the other columns
所以在C4的第3行有一个B和D.在C4之后仍然有很多列,由于我在脚本的其他部分需要它们,因此无法更改。
我有第二个输入文件,根据C3和C4中的字母,可以从中提取一些值。这是第二个输入文件的样子(这里是$frequency
)
C1 C2 A a B b C c D d
text 1 0 1 0 0 0 0 0 0
text 2 1 0 5 4 0 0 0 0
text 3 0 0 0 0 10 11 3 6
text 4 1 0 9 4 0 2 0 0
text 5 5 3 0 0 6 7 4 0
这就是我的输出结果:
C1 C2 C3 C4 C5 C6 C7 C8 C9 C10
text 2 A D 1 0 0 0 empty
text 4 B C 9 4 0 2 empty
text 5 A B,D 5 3 0 0 4 0
因此,对于第1行,C3中有A,然后脚本从$frequency
中提取A和a的值,并将它们放在C5和C6中。然后将来自C4的值放入输出文件中的C7和C8中。现在在第3行,C4中有B,D。所以脚本现在需要做的是将C和B中的B和b的相应值以及C和C10中的D和d的值。
我的脚本中唯一仍然存在问题的是在存在','时拆分此C4。其余的工作正在进行中。
这是我的脚本中有问题的部分看起来像
while(<$variants>){
next if /^\s*#/;
next if /^\s*"/;
chomp;
my ($chr, $pos, $refall, @altall) = split /\t/; # How should I specify here the C4, as an array? So that I don't know
my @ref_data = @{$frequency_data[$pos]}{$refall, lc($refall)};
my @alt_data = @{$frequency_data[$pos]}{$altall, lc($altall)}; # this works for C3 ($refall), but not for C4 when there are two letters
$pos = $#genes if $circular and $pos > $#genes; # adding annotation # this can be ignored here, since this line isn't part of my question
print join("\t","$_ ", $genes[$pos] // q(), @ref_data, @alt_data), "\n"; # printing annotation
}
所以有人可以帮我分解这个C4,&#39;&#39;并仍使用该信息从$variants
答案 0 :(得分:1)
我认为最简单的方法是将第3列和第4列视为一开始的列表:
while(<$variants>){
next if /^\s*#/;
next if /^\s*"/;
chomp;
my ($chr, $pos, $refall_string, $altall_string, @other) = split /\t/;
my @refall = split(",", $refall_string);
my @altall = split(",", $altall_string);
my @ref_data_all = (); # Treat C3 as array just in case...
foreach my $refall (@refall) {
push @ref_data_all, @{$frequency_data[$pos]}{ $refall, lc($refall) };
}
my @alt_data_all = ();
foreach my $altall (@altall) {
push @alt_data_all, @{$frequency_data[$pos]}{ $altall, lc($altall) };
}
$pos = $#genes if $circular and $pos > $#genes;
print join("\t","$_ ", $genes[$pos] // q(),
@ref_data_all, @alt_data_all), "\n";
}
我没有对此进行测试,但即使存在一些小错误,这种方法也应该清楚。
答案 1 :(得分:0)
您只需要进行几次map
来电。
如果你写
map { $_, lc } split /,/, $refall
然后你用任何逗号分割字段,并将每个字母复制为大写和小写。
这是完整的循环(已测试)。
while (<$variants>) {
next if /^\s*#/;
next if /^\s*"/;
chomp;
my ($chr, $pos, $refall, $altall) = split /\t/;
my $entry = $frequency_data[$pos];
my @ref_data = map { $entry->{$_} } map { $_, lc } split /,/, $refall;
my @alt_data = map { $entry->{$_} } map { $_, lc } split /,/, $altall;
$pos = $#genes if $circular and $pos > $#genes;
print join("\t","$_ ", $genes[$pos] // q(), @ref_data, @alt_data), "\n";
}