重複行をペアで削除しますか?

重複行をペアで削除しますか?

今日このユースケースを見つけました。一見すると簡単に見えますが、遊んでみるとsort簡単ではないことがわかりuniqますsedawk

どのようにすべて削除できますか?行が重複していますか?つまり、特定の行に対して偶数の重複行がある場合はすべて削除し、奇数の重複行がある場合は1行だけ残してすべて削除します。 (ソートされた入力を想定できます。)

清潔でエレガントなソリューションは、より良い選択です。

入力例:

a
a
a
b
b
c
c
c
c
d
d
d
d
d
e

出力例:

a
d
e

ベストアンサー1

sedこの質問を投稿した直後に回答が見つかりました。sedこれまで誰もこの質問を使用していないので、次のようになります。

sed '$!N;/^\(.*\)\n\1$/d;P;D'

より一般的な問題(3行、4行、または5行を削除するのはどうですか?)のより一般的な解決策は、次の拡張可能な解決策を提供します。

sed -e ':top' -e '$!{/\n/!{N;b top' -e '};};/^\(.*\)\n\1$/d;P;D' temp

展開して3行を削除します。

sed -e ':top' -e '$!{/\n.*\n/!{N;b top' -e '};};/^\(.*\)\n\1\n\1$/d;P;D' temp

または、クワッドラインを削除します。

sed -e ':top' -e '$!{/\n.*\n.*\n/!{N;b top' -e '};};/^\(.*\)\n\1\n\1\n\1$/d;P;D' temp

sedストリームで実際に動作できるという点で、他のほとんどのオプションと比較して追加の利点があり、重複しているかどうかを確認する実際の行数よりも多くのメモリ記憶領域は必要ありません。


〜のようにcuonglmがコメントで指摘しました、マルチバイト文字を含む行が誤って削除されないようにするには、ロケールをCに設定する必要があります。したがって、上記のコマンドは次のようになります。

LC_ALL=C sed '$!N;/^\(.*\)\n\1$/d;P;D' temp
LC_ALL=C sed -e ':top' -e '$!{/\n/!{N;b top' -e '};};/^\(.*\)\n\1$/d;P;D' temp
LC_ALL=C sed -e ':top' -e '$!{/\n.*\n/!{N;b top' -e '};};/^\(.*\)\n\1\n\1$/d;P;D' temp
# Etc.

おすすめ記事