.tsv
Linuxシステムには、さまざまなタイプ(文字列、数字)のカンマ区切り値を含む次の列を含む(タブ区切り列)ファイルがあります。
col1 col2
. NS,NS,NS,true,true
. 12,12,12,13
1,1,1,2 door,door,1,1
独自の価値を維持したいと思います(残念ながら試しましたが失敗しました)。出力は次のとおりです。
col1 col2
. NS,true
. 12,13
1,2 door,1
答え1
これは、値文字列を整数インデックスマップに分割して結合するMillerバリアントです。鍵カンマ区切り文字列に戻る):
mlr --tsv put 'for (k,v in $*) {
$[k] = joink(apply(splitnvx(v,","), func(k,v) {return{v:k}}),",")
}' file.tsv
またはperl5の助けを借りてリスト::ユーティリティ基準寸法:
perl -MList::Util=uniq -F'\t' -lpe '
$_ = join "\t", map { join ",", uniq split /,/, $_ } @F
' file.tsv
答え2
使用ミラー(mlr
)は各入力レコードのタブ区切りフィールドを繰り返し、フィールド値をコンマに分割し、各結果文字列を名前付きマップのキーとして追加し、最後にオーバーライドする区切り文字seen
としてコンマを使用してマップを連結します。します。フィールドseen
:
$ mlr --tsv put 'for (k,v in $*) { seen={}; for (i in splitax(v,",")) { seen[i]=1 } $[k] = joink(seen,",") }' file
col1 col2
. NS,true
. 12,13
1,2 door,1
ミラーのput
表情が美しくプリントされています。
for (k, v in $*) {
seen = {};
for (i in splitax(v, ",")) {
seen[i] = 1
}
$[k] = joink(seen, ",")
}
分割値をマップのキーとして追加すると、重複がなくなります。このsplitax()
関数は、各結果項目の型を推論することなく、区切り文字の文字列を配列に分割します(文字列になります)。このjoink()
関数はマップのキーを一緒に連結して、指定された区切り文字で区切られた文字列を形成します。外部ループのk
合計値は、v
それぞれフィールド名とその値です。
答え3
薄暗いPerlアプローチは次のとおりです。
$ perl -F'\t' -le '
%k=%l={};
print join("\t",
join(",",grep{++$k{$_}==1}split(/,/,$F[0])),
join(",",grep{++$l{$_}==1}split(/,/,$F[1]))
)' file.tsv
col1 col2
. NS,true
. 12,13
1,2 door,1
答え4
次のプログラムが実行されます(配列(1)awk
操作をサポートするすべての最近のAwk実装で動作する必要があります):delete
BEGIN{FS=OFS="\t"}
{
for (i=1;i<=NF;i++)
{
n=split($i,sf,",")
delete seen
fld=""
for (j=1;j<=n;j++)
{
if (!seen[sf[j]]++)
{
fld=fld (fld?",":"") sf[j]
}
}
$i=fld
}
print
}
たとえば、次のように保存してdedup.awk
呼び出します。
awk -f dedup.awk input.tsv
入力ファイルで作業します。
これにより、\t
入力フィールドと出力フィールドの区切り文字が設定されます。それではそうです。
for (i=1;i<=NF;i++)
行のすべてのフィールドを繰り返す()- 各フィールドをサブフィールドに分割(
sf
),
- すべてのサブフィールドを繰り返し、フィールドを一時変数として再組み立てします
fld
が、まだフィールドに表示されていないサブフィールド値のみを追加します。配列にレコードを保存しますseen
。 - 最後に再組み立てられたフィールドを
fld
現在のフィールドに割り当てます。$i
- これまでのすべての修正を含むライン全体を印刷します。
(1)最近サポートがかなり広がっていることを暗示してくれた@EdMortonに感謝します。