grep -n | sort | sed | cut
( export LC_ALL=C
grep -n '' | sort -t: -nmk1,1 ./L - |
sed /:/d\;n | cut -sd: -f2-
) <./F
Itu harus bekerja cukup cepat (beberapa tes waktunya termasuk di bawah ini) dengan input ukuran berapa pun. Beberapa catatan tentang caranya:
export LC_ALL=C
- Karena tujuan dari operasi berikut adalah untuk mendapatkan seluruh file yang
./F
ditumpuk sejajar dengan ./L
file lineno -nya , satu-satunya karakter yang benar-benar perlu kita khawatirkan adalah [0-9]
digit ASCII dan :
titik dua.
- Untuk alasan itu, lebih mudah untuk khawatir menemukan 11 karakter itu dalam 128 possible daripada jika UTF-8 terlibat.
grep -n ''
- Ini memasukkan string
LINENO:
ke kepala setiap baris di stdin - atau <./F
.
sort -t: -nmk1,1 ./L -
sort
sama sekali tidak menyortir file-file inputnya, dan sebaliknya (dengan benar) mengira file-file itu di - -m
presort dan menyesuaikannya dalam -numerically
urutan yang diurutkan, pada dasarnya mengabaikan apa pun yang melampaui karakter usus besar yang mungkin -k1,1
terjadi -t:
.
- Meskipun ini mungkin memerlukan beberapa ruang temp untuk dilakukan (tergantung pada seberapa jauh jarak beberapa urutan mungkin terjadi) , itu tidak akan memerlukan banyak dibandingkan dengan jenis yang tepat, dan itu akan sangat cepat karena melibatkan nol backtracking.
sort
akan menampilkan aliran tunggal di mana setiap lineno ./L
akan segera mendahului baris yang sesuai di ./F
. ./L
Garis selalu didahulukan karena lebih pendek.
sed /:/d\;n
- Jika baris saat ini cocok dengan
/:/
titik dua, d
hilangkan itu dari output. Lain, cetak otomatis jalur saat ini dan n
ext.
- Dan demikian,
sed
pangkas sort
output hanya untuk pasangan garis berurutan yang tidak cocok dengan titik dua dan baris berikut - atau, hanya untuk satu baris dari ./L
dan kemudian berikutnya.
cut -sd: -f2-
cut
-s
uppresses dari output mereka dari jalur input yang tidak mengandung setidaknya satu dari -d:
string elimiter - dan begitu juga ./L
garis dipangkas sepenuhnya.
- Untuk baris-baris yang ada, ield yang
:
dibatasi usus besar pertama mereka -f
ada cut
- dan begitu juga semua grep
lineno yang dimasukkan.
uji input kecil
seq 5 | sed -ne'2,3!w /tmp/L
s/.*/a-z &\& 0-9/p' >/tmp/F
... menghasilkan 5 baris input sampel. Kemudian...
( export LC_ALL=C; </tmp/F \
grep -n '' | sort -t: -nmk1,1 ./L - |
sed /:/d\;n | cut -sd: -f2-
)| head - /tmp[FL]
... mencetak ...
==> 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
tes waktunya lebih besar
Saya membuat beberapa file yang cukup besar:
seq 5000000 | tee /tmp/F |
sort -R | head -n1500000 |
sort -n >/tmp/L
... yang memasukkan 5 mil garis /tmp/F
dan 1,5 mil garis yang dipilih secara acak ke dalam /tmp/L
. Saya kemudian melakukan:
time \
( export LC_ALL=C
grep -n '' | sort -t: -nmk1,1 ./L - |
sed /:/d\;n | cut -sd: -f2-
) <./F |wc - l
Itu dicetak:
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
(Saya menambahkan garis miring terbalik di sana)
Di antara solusi yang saat ini ditawarkan di sini, ini adalah yang tercepat dari mereka semua tetapi satu ketika diadu dengan dataset yang dihasilkan di atas pada mesin saya. Yang lainnya hanya satu yang hampir bersaing untuk tempat kedua, dan itu meuh di perl
sini .
Ini sama sekali bukan solusi asli yang ditawarkan - ia telah menjatuhkan sepertiga dari waktu pelaksanaannya berkat saran / inspirasi yang ditawarkan oleh orang lain. Lihat riwayat kiriman untuk solusi yang lebih lambat (tapi mengapa?) .
Juga, perlu dicatat bahwa beberapa jawaban lain mungkin akan berpendapat lebih baik jika bukan karena arsitektur multi-CPU dari sistem saya dan eksekusi bersamaan dari setiap proses dalam pipa itu. Mereka semua bekerja pada saat yang sama - masing-masing pada inti prosesor sendiri - melewati data dan melakukan bagian kecil mereka secara keseluruhan. Itu sangat keren.
tetapi solusi tercepat adalah ...
Tetapi ini bukan solusi tercepat. Solusi tercepat yang ditawarkan di sini, tangan-down, adalah program C . Saya menyebutnya cselect
. Setelah menyalinnya ke clipboard X saya, saya mengompilasinya seperti:
xsel -bo | cc -xc - -o cselect
Saya kemudian melakukannya:
time \
./cselect /tmp/L /tmp/F |
wc -l
... dan hasilnya adalah ...
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