grep -n | sort | sed | cut
( export LC_ALL=C
grep -n '' | sort -t: -nmk1,1 ./L - |
sed /:/d\;n | cut -sd: -f2-
) <./F
これは、任意のサイズの入力で非常に迅速に動作するはずです(一部のタイミングテストが以下に含まれています)。方法に関する注意:
export LC_ALL=C
- 次の操作のポイントは、linenoのファイル
./F
とインラインでスタックされたファイル全体を取得することなので、./L
実際に心配する必要がある文字はASCII [0-9]
数字と:
コロンだけです。
- そのため、UTF-8が関係する場合よりも、128個の候補のセットでこれらの11文字を見つけることを心配する方が簡単です。
grep -n ''
- これにより、文字列
LINENO:
がstdin-またはの各行の先頭に挿入され<./F
ます。
sort -t: -nmk1,1 ./L -
sort
代わりに、すべての入力ファイルをソートするため無視して、(正しくは)彼らは事前にソートされている前提と-m
してそれらをerges -numerically
ソート順、基本的にすべての可能越えて何も無視して-k1,1
目が発生して-t:
、とにかくコロン文字を。
- これにはいくつかの一時スペースが必要になる場合がありますが(シーケンスの間隔によって異なります)、適切な並べ替えに比べてそれほど必要ではなく、バックトラッキングがゼロであるため非常に高速です。
sort
は、linenoのin ./L
がの対応する行の直前にある単一のストリームを出力し./F
ます。./L
の行は短いため、常に最初に表示されます。
sed /:/d\;n
- 現在の行が
/:/
コロンに一致する場合、d
出力からそれを選択します。そうでない場合は、現在のn
行とext行を自動印刷します。
- そのため、コロンと次の行に一致しない連続した行のペアのみに、または、次の行から次の行にのみ
sed
プルーニングsort
の出力が行われます。./L
cut -sd: -f2-
cut
-s
出力から、少なくとも1つの-d:
区切り文字列を含まない入力行の出力を抑制します./L
。したがって、の行は完全に削除されます。
- これらの行については、
:
コロンで区切られた最初の-f
フィールドがcut
離れているため、すべてのgrep
'挿入されたlineno'も同様です。
小入力テスト
seq 5 | sed -ne'2,3!w /tmp/L
s/.*/a-z &\& 0-9/p' >/tmp/F
... 5行のサンプル入力を生成します。その後...
( export LC_ALL=C; </tmp/F \
grep -n '' | sort -t: -nmk1,1 ./L - |
sed /:/d\;n | cut -sd: -f2-
)| head - /tmp[FL]
...プリント...
==> standard input <==
a-z 1& 0-9
a-z 4& 0-9
a-z 5& 0-9
==> /tmp/F <==
a-z 1& 0-9
a-z 2& 0-9
a-z 3& 0-9
a-z 4& 0-9
a-z 5& 0-9
==> /tmp/L <==
1
4
5
より大きな時限テスト
かなり大きなファイルをいくつか作成しました。
seq 5000000 | tee /tmp/F |
sort -R | head -n1500000 |
sort -n >/tmp/L
... /tmp/F
5mil 行を挿入し、1.5mil行をランダムに選択し/tmp/L
ます。私はそれから:
time \
( export LC_ALL=C
grep -n '' | sort -t: -nmk1,1 ./L - |
sed /:/d\;n | cut -sd: -f2-
) <./F |wc - l
印刷した:
1500000
grep -n '' \
0.82s user 0.05s system 73% cpu 1.185 total
sort -t: -nmk1,1 /tmp/L - \
0.92s user 0.11s system 86% cpu 1.185 total
sed /:/d\;n \
1.02s user 0.14s system 98% cpu 1.185 total
cut -sd: -f2- \
0.79s user 0.17s system 80% cpu 1.184 total
wc -l \
0.05s user 0.07s system 10% cpu 1.183 total
(そこにバックスラッシュを追加しました)
ここで現在提供されているソリューションの中で、これはすべての中で最速ですが、私のマシンで上記で生成されたデータセットと比較した場合のものです。他の人の中で、2位争いに近づいたのは1人だけで、それがperl
ここにあります。
これは決して元のソリューションが提供するものではありません-他の人から提供されたアドバイスやインスピレーションのおかげで、実行時間の3分の1が短縮されました。遅いソリューションについては投稿履歴を参照してください(しかし、なぜですか?)。
また、システムのマルチCPUアーキテクチャとそのパイプライン内の各プロセスの同時実行に対応していなければ、他の回答がより適切に競合する可能性があることに注意してください。それらはすべて同時に動作します-それぞれ独自のプロセッサコア上で-データをやり取りし、全体の小さな部分を実行します。超カッコイイ。
しかし、最速のソリューションは...
しかし、それは最速のソリューションではありません。ここで提供される最速のソリューションは、Cプログラムです。私はそれを呼んだcselect
。Xクリップボードにコピーした後、次のようにコンパイルしました。
xsel -bo | cc -xc - -o cselect
私はそれから:
time \
./cselect /tmp/L /tmp/F |
wc -l
...そして結果は...
1500000
./cselect /tmp/L /tmp/F \
0.50s user 0.05s system 99% cpu 0.551 total
wc -l \
0.05s user 0.05s system 19% cpu 0.551 total