1

12列のtxtファイルがあります。一部の行は重複しており、一部は重複していません。例として、データの最初の 4 列にコピーしました。

0       0       chr12   48548073  
0       0       chr13   80612840
2       0       chrX    4000600 
2       0       chrX    31882528 
3       0       chrX    3468481 
4       0       chrX    31882726
4       0       chr3    75007624

最初の列に基づいて、エントリ '3' を除いて重複があることがわかります。この場合は「3」という単一のエントリのみを印刷したいと思います。

出力は次のようになります。

3       0       chrX    3468481

awkまたはperlでこれを行う簡単な方法はありますか? perl で for ループを使用することしか考えられませんが、約 150 万のエントリがあるという事実を考えると、おそらく時間がかかります。

4

5 に答える 5

2

ワンライナーではありませんが、この小さな Perl スクリプトは同じタスクを実行します。

#!/usr/bin/perl
use strict;
use warnings FATAL => 'all';

# get filehandle
open( my $fh, '<', 'test.txt');

# all lines from your file
my %line_map; 

while( my $line = <$fh> ) { # read a line

   my $key;
   my @values;

   # split on whitespace
   ($key, @values) = split(/\s+/, $line);

   # delete a line if it already exists in the map
   if( exists $line_map{$key} ) {
       delete $line_map{$key};
   } 
   else { # mark a line to show that it has been seen
      $line_map{$key} = join("\t", @values);
   }
}

# now the map should only contain non-duplicates
for my $k ( keys %line_map ) {
   print "$k\t", $line_map{$k}, "\n"; 
}
于 2013-07-10T13:11:21.180 に答える
1

コメントを適切にフォーマットできません。@JS웃はGNUに依存している可能性がありますuniq...これはBSD派生バージョンで機能するようです:

grep ^`cut -d" " -f1 col_data.txt  | uniq -u` file.txt

perlもっと短い答えが必要です:-)

于 2013-07-10T20:33:53.527 に答える
0

perlワンライナーの応答があるに違いないことはわかっていました。ここにあります-十分にテストされていないため、emptorに注意してください ;-)

perl -anE 'push @AoA,[@F]; $S{$_}++ for @F[0];}{for $i (0..$#AoA) {for $j (grep {$S{$_}==1} keys %S) {say "@{$AoA[$i]}" if @{$AoA[$i]}[0]==$j}}' data.txt

このアプローチの欠点は、わずかに変更された形式でデータを出力し (これは簡単に修正できると思います)、2 つのforループと「バタフライ演算子」(!!) を使用することですgrep()。 -つまり、自分でループをコーディングする必要がない場合でもコードが実行されるものです)。そのため、150 万レコードでは遅くなる可能性があります。awkと比べて見てみたいですけどねuniq

プラス面では、モジュールを使用せず、Windows と OSX で実行する必要があります。これは、一意の最初の列を持つ類似のレコードが数十ある場合に機能し、一意の行をチェックする前に入力をソートする必要はありません。解決策は、Joseph Hall、Joh McAdams、およびbrian d foyによる『 Effective Perl Programming』の終わり近くにあるワンライナーの例からほとんど 引用されています(素晴らしい本です。スマート マッチとほこりが落ち着いたら、新しい版が登場することを願っています)。~~given when

これがどのように機能するかです(私は思う):

  • 使用し-aているため、@F配列を無料で取得できるため、分割する代わりにそれを使用します
  • を使用し-nているwhile() {}ためループ内にいるためpush、の要素は参照の無名配列として使用@Fされます ( は「無名配列コンストラクター」として機能します)。そうすれば、彼らはたむろし、後で参照できます(これは意味がありますか???)@AoA[]
  • 上記の本の$seen{$_}++イディオム ($S代わりにを使用) を使用し、ここで @Axeman$seenによって非常によく説明されているSOの一意の要素を調べ、要素を表示する回数に応じてハッシュのキーを設定/インクリメントします(または行) を与えられた値 (つまり、行の内容) に置き換えます。@F[0]%S
  • 「バタフライ」}{を使用してから抜け出しwhile、別のブロックで、2 つのforループを使用して外側の配列を調べ、各要素 (それ自体が無名配列$iで、行ごとに 1 つ) を調べてから、内部の各無名配列を調べます。前に作成したハッシュ ( 、または内側のループ) で「1」に等しいgrep値が含まれる配列で、これらの値を に連続して配置します。keys%Sfor $j (grep {$S{$_}==1} keys %S)$j
  • 最後に、外側の配列を繰り返し処理し、その配列の最初の要素が各 ( ) の値と等しい無名配列を出力します$j。( ) でそれを行います@{$AoA[$i]}[0]==$j

awk@Kentの手にあるのはもう少し気の利いたものです。私の「回線ノイズ」を短縮または文書化する方法について誰かが提案を持っている場合 (そして、私は決してそれについては言いませんperl!) 建設的なコメントを追加してください!

読んでくれてありがとう。

于 2013-07-14T20:59:27.830 に答える