web-dev-qa-db-ja.com

特定の用語を含む行の列の合計

同一の識別子を持つ行のすべての列を合計できるsedまたはawkコマンドがあるかどうか疑問に思います。たとえば、私のファイルdata.txtは、約1800列のデータと約1400行が含まれていることを除いて、以下のように設定されています。

ABCD:1234  1.23  0.23  0.83   0
ABCD:1234    0    1.10  0.21   0 
EFGH:5678    0    1.90  0.12  8.21
IJKL:9999    1.22  0    1.84  9.21
IJKL:9999    1.44  0   12.94   0
IJKL:9999    1.32  0   24.12   2.43

そして、コマンドの後にどのようにしたいかは次のようになります。

ABCD:1234  1.23  1.33  1.04  0
EFGH:5678    0    1.90  0.12  8.21
IJKL:9999   3.98   0   38.9  11.64

これがawkまたはsedでさえ可能かどうかはわかりません(私は生物学者であり、まだUnixの基礎を学んでいます)。どんな助けでも大歓迎です。

2
DiscoA

入力ファイルまたは結果テーブル全体をメモリに保持しないawkスクリプト:

FNR == 1   { for(i = 1; i <= NF; i++) a[i] = $i;  next }
$1 == a[1] { for(i = 2; i <= NF; i++) a[i] += $i; next }
{
    printf "%s", a[1]; a[1] = $1;
    for(i = 2; i <= NF; i++) { printf "\t%s", a[i]; a[i] = $i };
    printf "\n";
}
END {
    printf "%s", a[1];
    for(i = 2; i <= NF; i++) printf "\t%s", a[i];
    printf "\n";
}

それを実行するには:

awk -f script.awk data.txt

結果:

ABCD:1234       1.23    1.33    1.04    0
EFGH:5678       0       1.90    0.12    8.21
IJKL:9999       3.98    0       38.9    11.64

ちなみに、実際にはsedでそれを行うことが可能です。しかし、あなたはすぐにそれをすることはないでしょう。理由については、 ここ を参照してください。

4
Satō Katsura

Perlを使用した代替ソリューション

$ Perl -nale '
if(!$seen{$F[0]}++)
{
    print join "\t", @a if @a;
    @a = @F[0..$#F];
}
else
{
    $a[$_] += $F[$_] foreach(1..$#F);
}
print join "\t", @a if eof;
' data.txt 
ABCD:1234   1.23    1.33    1.04    0
EFGH:5678   0       1.90    0.12    8.21
IJKL:9999   3.98    0       38.9    11.64
  • -aは入力行をスペースに分割し、それらを@F配列に保存します
  • 行の最初のフィールドは、変数%seenをハッシュするためのキーとして使用されます。キーが見つからない場合は、@a配列の内容が空でない場合は出力し、配列に改行のフィールドを割り当てます。
  • キーがすでに存在する場合は、配列の内容を(2番目のフィールドから最後まで)現在の行の対応する内容でインクリメントします
  • 最後のエントリを処理するには、ファイルの終わりに達したときに@a配列の内容を再度出力します


重複する質問の場合: 最初の列に同じエントリがある場合、Linuxではすべての列を個別に追加します

$ Perl -nale '
if(!$seen{$F[0]}++)
{
    print join "\t", @a if @a;
    @a = @F[0..$#F];
}
else
{
    $a[$_] += $F[$_] foreach(1..$#F);
}
print join "\t", @a if eof;
' filename.txt 
AC1481523   6   6   6   6
AC1481676   6   5   6   8


配列のハッシュを作成し、最後にハッシュを出力するソリューション:

$ Perl -nale '
if($h{$F[0]})
{
    $h{$F[0]}[$_] += $F[$_] foreach (1..$#F)
}
else
{
    $h{$F[0]} = [@F]
}
END { print join "\t",@{$h{$_}} foreach sort keys %h }
' data.txt
ABCD:1234   1.23    1.33    1.04    0
EFGH:5678   0       1.90    0.12    8.21
IJKL:9999   3.98    0       38.9    11.64
0
Sundeep