1

このような状況に直面するのはこれが初めてです。最初のフィールドだけに uniq を実行する必要がありますが、重複した行の内容を削除する必要はありません。この例を見てください

入力ファイル

ENST000001.1    +   67208778    67210057
ENST000001.1    +   67208778    67210768
ENST000001.1    +   67208778    67208882
ENST000002.5    +   67208778    67213982
ENST000003.1    -   57463571    57463801
ENST000003.1    -   57476352    57476463
ENST000003.1    -   57476817    57476945

(uniq -w 12) を実行すると、最初のフィールド (12 文字しかない) だけが、他のすべての行で重複がないかチェックされます。結果は次のようになります。

ENST000001.1    +   67208778    67210057
ENST000002.5    +   67208778    67213982
ENST000003.1    -   57463571    57463801

重複するすべての行の内容は破棄され、最初の行だけが残ります。私が探しているのはこのようなものです

ENST000001.1    +   67208778_67210057  67208778_67210768  67208778_67208882 
ENST000002.5    +   67208778_67213982
ENST000003.1    -   57463571_57463801  57476352_57476463  57476817_57476945   

重複した行の内容を失わずに uniq を使用するにはどうすればよいですか?! AWK/sed/perl でそれを行う方法はありますか?

4

4 に答える 4

3
awk '{a[$1" "$2]=a[$1" "$2]" "$3" "$4;}END{for(i in a)print i,a[i]}' your_file

以下でテスト:

> cat temp
ENST000001.1    +       67208778        67210057
ENST000001.1    +       67208778        67210768
ENST000001.1    +       67208778        67208882
ENST000002.5    +       67208778        67213982
ENST000003.1    -       57463571        57463801
ENST000003.1    -       57476352        57476463
ENST000003.1    -       57476817        57476945
> awk '{a[$1" "$2]=a[$1" "$2]" "$3" "$4;}END{for(i in a)print i,a[i]}' temp
ENST000002.5 +  67208778 67213982
ENST000003.1 -  57463571 57463801 57476352 57476463 57476817 57476945
ENST000001.1 +  67208778 67210057 67208778 67210768 67208778 67208882

_underscore( )について具体的に説明する場合は、以下を使用してください。

> awk '{a[$1" "$2]=a[$1" "$2]" "$3"_"$4;}END{for(i in a)print i,a[i]}' temp
ENST000002.5 +  67208778_67213982
ENST000003.1 -  57463571_57463801 57476352_57476463 57476817_57476945
ENST000001.1 +  67208778_67210057 67208778_67210768 67208778_67208882
> 

説明:

->キーが最初のフィールド+スペース+2番目のフィールドになる連想配列aを作成します。

-> 各キーの値は、前の値 + 3 番目のフィールド + アンダースコア + 4 番目のフィールドです。

→すべての行を処理した後、end ブロックが実行されます。for ループは ass..array をループし、そのキーと値を出力します。

perl もタグ付けされているため、perl ソリューションは次のとおりです。

perl -F -lane '$H{$F[0]." ".$F[1]}=$H{$F[0]." ".$F[1]}." ".$F[2]."_".$F[3];if(eof){foreach(keys %H){print $_,$H{$_}}}' your_file

上記の perl ソリューションは、コマンド ライン自体で動作します。

于 2012-12-27T12:00:40.437 に答える
1

Perl では、それらを hashref にグループ化することでそれを行うことができます。

#!/usr/bin/perl
use strict;
use warnings;

my $lines;
while (<DATA>) {
  chomp;
  my @fields = split /\s+/;
  push @{ $lines->{"$fields[0] $fields[1]"} }, "$fields[2]_$fields[3]";
}

foreach my $line (sort keys %$lines) {
  print join("\t", $line, @{ $lines->{$line} }), "\n";
}
__DATA__
ENST000001.1    +   67208778    67210057
ENST000001.1    +   67208778    67210768
ENST000001.1    +   67208778    67208882
ENST000002.5    +   67208778    67213982
ENST000003.1    -   57463571    57463801
ENST000003.1    -   57476352    57476463
ENST000003.1    -   57476817    57476945
于 2012-12-27T12:06:57.233 に答える
0

これがPerlのワンライナーです:

perl -lane 'BEGIN{$"=v9}push@{$u{"@F[0,1]"}},"$F[2]_$F[3]"}{while(($k,$v)=each%u){print"@{[$k,@$v]}"}'

拡張バージョン:

#!/usr/bin/env perl
use strict;
use warnings;
BEGIN { $/ = "\n"; $\ = "\n"; $" = "\t" }
my %u;
while (<ARGV>) {
    chomp;
    my @F = split /\s+/;
    push @{$u{"@F[0, 1]"}}, "$F[2]_$F[3]";
}
while (my ($k, $v) = each %u) {
    print "@{[$k, @$v]}";
}
于 2012-12-27T12:13:34.010 に答える
0

これはあなたのために働くかもしれません(GNU sed):

sed -r ':a;$!N;s/^((\S+\s+\S+).*)\n\2/\1/;ta;s/\<([0-9]+)\s+([0-9]+)\>/\1_\2/g;P;D' file
于 2012-12-27T13:45:57.150 に答える