2つのフィールドを持つ大きなファイルがあります。最初のフィールドはオブジェクト名を表し、2番目のフィールドはそのオブジェクトのサイズを表します。
A 1
A 2
B 4
ABC 12
C 5
A 9
B 3
ABC 6
リストを次の形式にまとめたいと思います。
A 1,2,9
ABC 12,6
B 4,3
C 5
私が考えた解決策は、ファイル内に独自のオブジェクトのリストを作成し、それを繰り返して元のファイルと一致させることでした。
for object in $(awk '{print $1}' objects_with_sizes.txt | sort -u);do
echo -n "$object "
awk -v pattern="$object" '$1==pattern{printf "%s%s" ,sep,$2;sep=","} END{print ""}' objects_with_sizes.txt
done
この実装は実行に時間がかかります。希望の出力を生成するより効率的な方法はありますか?
答え1
$ awk '{ object[$1]= (object[$1]==""?"":object[$1] ",") $2 }
END { for(obj in object) print obj, object[obj] }' infile
A 1,2,9
B 4,3
C 5
ABC 12,6
より効率的に(メモリを使用し、メモリに収まらない大容量ファイルにとって重要です)、awkコマンドのみを使用して、上記のようにファイル部分をバッファリングせずにオブジェクトキーが変更されるまでのみバッファリングすることです。
$ <infile sort -k1,1 -k2,2n |\
awk 'pre!=$1 { if(obj) { print obj; obj="" } }
{ obj= (obj==""?$1 " ":obj ",") $2; pre=$1 }
END{ if(obj) print obj }'
A 1,2,9
ABC 6,12
B 3,4
C 5
答え2
GNUの使用datamash
:
$ datamash -t ' ' -s -g 1 collapse 2 <file
A 1,2,9
ABC 12,6
B 4,3
C 5
オプション:
-t '_'
フィールド区切り文字でスペース文字を使用する-s
グループ化前の入力ソート-g 1
最初のフィールドのグループcollapse 2
2番目のフィールドの値をカンマ区切りリストに縮小します。
答え3
並べ替えてGNU sedに入力すると、現在の最初のフィールドを前のフィールドと比較して、その点までカンマ区切りのORを印刷します。
$ < file sort -s -k1,1 \
| sed -Ee '
:a
$!N
s/^((\S+)\s.*)\n\2\s+(\S+)/\1,\3/
ta
P;D
' -
A 1,2,9
ABC 12,6
B 4,3
C 5