列2が列1の2つ以上の値に対応する場合は、すべての行を削除します。

列2が列1の2つ以上の値に対応する場合は、すべての行を削除します。

次のタブで区切られたテーブルがあります。

GL89     AADAC
GL89     AFGAC
GL89     AFDAC
GL50     AC923
GL50     AC923
GL79     AC923
GL99     AC923
GL99     AC923
GL60     AC100
GL60     AC100
GL20     AC200
GL30     AC300
GL30     AC400

2列の値の1つ以上が1列の2つ以上の値に対応する行を削除したい場合は、この場合は次の行を削除する必要があります。

GL50     AC923
GL79     AC923
GL99     AC923
GL99     AC923

残りのテーブルは維持してください。

GL89     AADAC
GL89     AFGAC
GL89     AFDAC
GL60     AC100
GL60     AC100
GL20     AC200
GL30     AC300
GL30     AC400

フォームがありますか?ありがとうございます!

答え1

awk 'BEGIN{ FS=OFS="\t" }
{ data[$2]= (data[$2]==""?"":(k[$2]==$1? data[$2] ORS: "@") ) $0; k[$2]=$1 }

END{ for(x in data) if(data[x] !~/^@/) print data[x] }' infile

注:印刷時に印刷しないレコードを表示するために文字を使用しているため、@この文字は入力ファイルではありません。それ以外の場合は別のものに変更する必要があります(または次の文字セットを選択してください)。代わりに文字列)。

  • data[$2]= (data[$2]==""?"":(XXX) ) $0、配列が空でない場合は、そのセクションのdata結果として配列値を更新し、現在の行を追加します。(XXX)この列は$2配列キーとして使用されます。

  • (XXX)(k[$2]==$1? data[$2] ORS: "@")同じキーの値(キーの最新の値のペアを維持するために配列をヘルパーとして使用)が異なる場合は、atシンボル文字が設定され、それ以外の場合はキーにt内容+改行文字(ORS)が追加されます。 )。

  • @最後に、2番目の列は同じですが、最初の列が1つ以上の他のすべての行は、コード内の特定の文字でマークされているため削除されます。


コードをよりよく理解するために、print ...いつでもこのステートメントを使用して何が起こっているのかを確認できます。

awk 'BEGIN{ FS=OFS="\t" }
{ data[$2]= (data[$2]==""?"":(k[$2]==$1? data[$2] ORS: "***") ) $0; k[$2]=$1 }

END{ for(x in data) print "<" data[x] ">" }' infile

元のコマンドから削除されたレコードをat記号で表示し、その***マークで始まるレコードがここに表示されます。

答え2

サポートされているawkを使用してくださいlength(array)

$ cat tst.awk
BEGIN { FS=OFS="\t" }
$2 != prev {
    if ( NR > 1 ) {
        prt()
    }
    prev = $2
}
{ cnt[$1]++ }
END { prt() }

function prt(   val,i) {
    if ( length(cnt) == 1 ) {
        for (val in cnt) {
            for (i=1; i<=cnt[val]; i++) {
                print val, prev
            }
        }
    }
    delete cnt
}

$ sort -t$'\t' -k2,2 -k1,1 file | awk -f tst.awk
GL89    AADAC
GL60    AC100
GL60    AC100
GL20    AC200
GL30    AC300
GL30    AC400
GL89    AFDAC
GL89    AFGAC

答え3

この問題に適したデータ構造は次set のとおりです。dictionary

そして、Pythonにはこれら両方の機能が組み込まれています。

python3 -c 'import sys
ifile = sys.argv[1]
fs,ors = "\t","\n"

d = {}; L = {}
with open(ifile) as fh:
  for l in fh:
    c1,c2 = l.rstrip().split(fs)
    if c2 in d:
      d[c2].add(c1)
      L[c2].append(l.rstrip())
    else:
      d[c2] = { c1 }
      L[c2] = [ l.rstrip() ]

print(*[l
  for k,v in d.items()
  if len(v) == 1
  for l in L[k]
  ], sep=ors)
' file

出力:

GL89    AADAC
GL89    AFGAC
GL89    AFDAC
GL60    AC100
GL60    AC100
GL20    AC200
GL30    AC300
GL30    AC400

答え4

ただ楽しみのために1 使用してくださいミラー

基本的な手順は次のとおりです。

  1. nest --implodeそれぞれに対応するすべての値を別々のリストにまとめるために使用されます。$1$2

  2. 一意の値を計算するフィルタのリスト$1

  3. nest --explodeフィルタリングされた値を$1別々のレコードに拡張するために使用されます。

GL50;GL50;GL79;GL99;GL99(2)ステップでは、ハッシュマップのキーに変換するのと同じように、区切りリストから重複する要素を削除できます。残念ながら、組み込みDSL文字列 - ハッシュマップ関数はキー値でのみ機能しますsplitkvsplitkvx- 別々の区切りキー文字列をハッシュマップ(任意またはnull値を含む)に変換する方法(例:nullペア区切り文字の渡し)がないようです。したがって、文字列をインデックスマップに分割して独自のマップをロールバックする必要があります。価値新しい地図に入場するための鍵です。

(2)と(3)のステップは、私たちが必要とするので、必要であることに注意してください。いいえ複数の値をフィルタリングしたい。同じ $1値 - それ以外の場合は、単純に拡張された文字列のインデックスマップの長さをテストできます(そして分解された結果は必要ありません)。

だから

$ mlr --nidx --fs tab nest --ivar ';' -f 1 then filter '
  func splitkx(s,t):map {
    var m = {};
    for(k,v in splitnvx(s,t)){m[v] = 1};
    return m
  }
  length(splitkx($1,";")) == 1' then nest --evar ';' -f 1 file
GL89    AADAC
GL89    AFGAC
GL89    AFDAC
GL60    AC100
GL60    AC100
GL20    AC200
GL30    AC300
GL30    AC400

メモ:

  1. もう一度調べることができるかどうか疑わしいので、私の参考のためにより多くの情報を提供します。

関連情報