3

テキスト ファイルを使用するスクリプトを作成しています。1 つの列には、「,」で区切られた 2 つの文字 (A、B、C、または D) が含まれます。この列には、これらの文字の 1 つだけを含めることもできます。スクリプトの残りの部分でさらに計算を行うには、両方の文字を使用する必要があります。これは私の入力ファイルの単純化された例です (こちら$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 に存在する文字に基づいて、いくつかの値が抽出される 2 番目の入力ファイルがあります。これは、この 2 番目の入力ファイルがどのように見えるかです (こちら$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 があり、スクリプトは A と a の値を抽出$frequencyして C5 と C6 に配置します。C4 からの値は、出力ファイルから C7 と C8 に入れられます。3 行目には、C4 に B,D があります。したがって、スクリプトが次に行う必要があるのは、B と b の対応する値を C7 と C8 に配置し、D と d の値を C9 と C10 に配置することです。

私のスクリプトでまだ問題がある唯一のことは、',' がある場合にこの 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を「、」で分割するのを手伝ってくれて、それでも値を抽出するために情報を使用できますか$variants

4

2 に答える 2

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";
}

私はこれをテストしませんでしたが、小さなバグがあってもアプローチは明らかです。

于 2013-08-30T13:03:30.087 に答える
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";
}
于 2013-08-30T15:06:32.703 に答える