Ansatzの備忘録

勉強したことあるいはふと思い立ったこと

シェルワンライナー160本ノック問題45

問題45 複数行にわたる重複の検索

問題のファイルは

https://github.com/shellgei/shellgei160

からダウンロードできる。

重複の扱い方がまったくわからず解けなかった。

解答例は

awk 'NF{print NR,"\0"$0}' sh_highschool | sort -k2,2 | uniq -f 1 -D | sort -k1,1n | awk -F '\0' 'n+1!=$1{print t,"\0",ns;t=ns=""}{n=$1;t=t$2;ns=ns n}END{print t,"\0",ns}' | awk -F '\0' '{a[$1]=a[$1] ? a[$1]"-"$2 : $2}END{for(k in a)print a[k]}' | awk NF | sed 's/^ //'

となる。最初の awk で空行を除いて行番号とテキストをセットで出力する。また行番号とテキストの間にヌル文字を入れている。そのあと重複している行を sort で抜き出している。ちょっと整形した後、2番目の awk でテキストが連続して出てくるまとまりごとにまとめて、行番号も後ろにくっつけてある。この awk では最初のアクションが初めて実行されるとき、t, ns は空文字列として初期化されるので何も出力されない。2番目のアクション以降でいろいろ代入されてから、行番号が不連続に変化したときに1番のアクションが実行される。最後の awk は a[$1] に三項演算子 a[$1] ? a[$1]"-"$2 : $2 の結果を代入している。a[$1] の $1 はテキストである。配列 a の中身は最初は空なので a[$1] は0となり条件が偽となるため $2 の代入が行われるが、2回目に同じテキストが出てきたとき配列にはすでに行番号が入っているので条件は真となり a[$1]"-"$1 が配列に代入される。最後にまとめて配列の中身を出力する。