次のタブで区切られたテーブルがあります。
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 、使用してくださいミラー
基本的な手順は次のとおりです。
nest --implode
それぞれに対応するすべての値を別々のリストにまとめるために使用されます。$1
$2
一意の値を計算するフィルタのリスト
$1
nest --explode
フィルタリングされた値を$1
別々のレコードに拡張するために使用されます。
GL50;GL50;GL79;GL99;GL99
(2)ステップでは、ハッシュマップのキーに変換するのと同じように、区切りリストから重複する要素を削除できます。残念ながら、組み込みDSL文字列 - ハッシュマップ関数はキー値でのみ機能しますsplitkv
。splitkvx
右- 別々の区切りキー文字列をハッシュマップ(任意または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
メモ:
- もう一度調べることができるかどうか疑わしいので、私の参考のためにより多くの情報を提供します。