この問題に対する perl または awk の解決策はありますか?

この問題に対する perl または awk の解決策はありますか?

入力ファイル(入力.txt)を以下のように入力します。

id1      id2       name    weight 
53723848 12651711 timburnes 1.36667
53530214 12651711 timburnes 1.51191
53723848 53530214 timburnes 1.94
764157 52986038 ericcartman 0.861145
56797854 764157 ericcartman 1.35258
56797854 52986038 ericcartman 1.73781

ご了承ください最初の行は実際のファイルの一部ではありませんが、わかりやすくするためにここに追加しました。

id1との値をid22つの別々のファイルに抽出しようとしています。ユニーク.txtそして重複.txt

weight列の値が1.5より大きい場合は、重複したIDこの場合、値をファイルid1に移動し、値をファイルに移動します。unique.txtid2duplicate.txt

重みの列が1.5未満の場合、重複した値がないことを意味します。この場合、とid1id2両方を ユニーク.txtファイル。

したがって、上記の入力に対して、次のような出力が期待されます。

のためにユニーク.txtファイル、

53723848 timburnes
764157 ericcartman
56797854 ericcartman

のために重複.txtファイル、

12651711 timburnes
53530214 timburnes
52986038 ericcartman

以下のコードを使用して重複を見つけることができます。

4列目に基づいて1.5より大きい値を取得するには、

awk -F" " '$4 >= 1.5 { print $1" " $2" " $3" " $4}' file1.txt > Output.txt

ここで、値が 1.5 より大きい場合は、以下のコードを使用して、名前に基づいて重複する ID をマージできます。

  perl -ane 'foreach(@F[0..1]){$k{$F[2]}{$_}++}
           END{
                foreach $v (sort keys(%k)){
                    print "$_ " foreach(keys(%{$k{$v}})); 
                    print "$v\n"
                }; 
            } ' Output.txt

しかし、上記のアプローチでは、希望どおりの出力を得ることができません。

編集:

以下のように入力してコマンドを実行しています。

awk '{
      if ($4 > 1.5) { 
          if (++dup[$2] == 1)  print $2, $3 > "duplicate.txt"
      } 
      else
          if (++uniq[$1] == 1) print $1, $3 > "unique.txt" 
}' << END
17412193 43979400 ericcartman 2.16667
21757330 54678379 andrewruss 0.55264
END 

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

-bash-3.2$ cat unique.txt
21757330 a.andreev
-bash-3.2$ cat duplicate.txt
43979400 ericcartman

しかし、私が期待している出力は、

cat unique.txt
17412193 ericcartman
21757330 andrewruss
54678379 andrewruss
cat duplicate.txt
43979400 ericcartman

答え1

解決策は次のとおりですawk:

$ awk '
    $4 < 1.5 {
      uniq[$1] = $3;
      uniq[$2] = $3;
      next;
  }
  {
      uniq[$1] = $3;
      dup[$2] = $3;
      delete uniq[$2];
  }
  END {
    print "--unique.txt--";
    for(i in uniq) {
        print i,uniq[i]
    }
    print "";
    print "--duplicate.txt--";
    for(i in dup) {
        print i,dup[i]
    }
    }' file
--unique.txt--
764157 ericcartman
56797854 ericcartman
53723848 timburnes

--duplicate.txt--
53530214 timburnes
52986038 ericcartman
12651711 timburnes

2番目の例:

$ awk '
    $4 < 1.5 {
      uniq[$1] = $3;
      uniq[$2] = $3;
      next;
  }
  {
      uniq[$1] = $3;
      dup[$2] = $3;
      delete uniq[$2];
  }
  END {
    print "--unique.txt--";
    for(i in uniq) {
        print i,uniq[i]
    }
    print "";
    print "--duplicate.txt--";
    for(i in dup) {
        print i,dup[i]
    }
    }' << END
> 17412193 43979400 ericcartman 2.16667
> 21757330 54678379 andrewruss 0.55264
END
--unique.txt--
21757330 andrewruss
54678379 andrewruss
17412193 ericcartman

--duplicate.txt--
43979400 ericcartman

答え2

$ awk '{
      if ($4 > 1.5) { 
          if (++dup[$2] == 1)  print $2, $3 > "duplicate.txt"
      } 
      else
          if (++uniq[$1] == 1) print $1, $3 > "unique.txt" 
}' << END
53723848 12651711 timburnes 1.36667
53530214 12651711 timburnes 1.51191
53723848 53530214 timburnes 1.94
764157 52986038 ericcartman 0.861145
56797854 764157 ericcartman 1.35258
56797854 52986038 ericcartman 1.73781
END

$ cat unique.txt 
53723848 timburnes
764157 ericcartman
56797854 ericcartman

$ cat duplicate.txt 
12651711 timburnes
53530214 timburnes
52986038 ericcartman

答え3

以下は Perl の例です:

perl -lane '$F[3]>1.5 ? print STDERR "$F[1] $F[2]" : print STDOUT "$F[0] $F[2]"'\
 input.txt 2> duplicate.txt > unique.txt

ここでは重複をチェックしていません。質問を正しく理解していれば、すでに重複をチェックしており、重複しているかどうかは最後のフィールドの値によって決まります。私が誤解している場合はお知らせください。更新します。

上記のコードは

$ cat duplicate.txt 
12651711 timburnes
53530214 timburnes
52986038 ericcartman

$ cat unique.txt 
53723848 timburnes
764157 ericcartman
56797854 ericcartman

関連情報