grep -n | sort | sed | cut
( export LC_ALL=C
grep -n '' | sort -t: -nmk1,1 ./L - |
sed /:/d\;n | cut -sd: -f2-
) <./F
Bu , herhangi bir boyutta girdi ile oldukça hızlı bir şekilde çalışmalıdır (bazı zamanlanmış testler aşağıdadır) . Nasıl yapılacağına dair bazı notlar:
export LC_ALL=C
- Aşağıdaki işlemin amacı,
./F
yığılmış dosyanın tamamını ./L
lineno'nun dosyasıyla satır içine almak olduğundan , endişelenmemiz gereken tek karakter ASCII [0-9]
basamakları ve :
iki nokta üst üste işaretidir.
- Bu nedenle, 128 olasılık setinde bu 11 karakteri bulma konusunda endişelenmek UTF-8'in başka şekilde dahil edilmesinden daha kolaydır.
grep -n ''
- Bu, dizeyi
LINENO:
stdin'deki her satırın başına ekler - veya <./F
.
sort -t: -nmk1,1 ./L -
sort
ihmaller hiç onun girdi dosyaları sıralamak ve bunun yerine etmek (doğru) onlar ön ayrımı olan varsaymaktadır ve -m
bunları erges -numerically
temelde olası ötesinde bir şey yok sayarak, sıralı düzende -k1,1
st meydana gelen -t:
neyse kolon karakteri.
- Bu, yapılması gereken geçici bir alan gerektirse de (bazı dizilerin ne kadar ayrı olabileceğine bağlı olarak) , uygun bir sıralama ile karşılaştırıldığında çok fazla gerekmeyecektir ve çok hızlı olacaktır, çünkü sıfır geri izlemeyi içerir.
sort
herhangi bir lineno'nun ./L
içindeki ilgili satırlardan hemen önce geleceği tek bir akış çıkarır ./F
. ./L
çizgileri her zaman önce gelir çünkü daha kısadırlar.
sed /:/d\;n
- Geçerli satır bir
/:/
iki nokta üst üste ile d
eşleşirse çıkıştan alır. Aksi takdirde, geçerli ve n
dahili satırı otomatik olarak yazdırın .
- Ve böylece
sed
kuru erik sort
, yalnızca iki nokta üst üste ve bir sonraki satırla eşleşmeyen sıralı satır çiftlerine veya yalnızca bir ./L
sonraki satırdan sonra bir satıra çıktı verir .
cut -sd: -f2-
cut
-s
elimiter -d:
dizelerinden en az birini içermeyen girdi çizgilerinin çıktılarından yukarı doğru baskı yapar ve böylece ./L
hatları tamamen budanır .
- Bunu yapan hatlar için, ilk
:
kolonla sınırlandırılmış -f
alanı cut
uzaktadır - ve böylece grep
sokulan tüm linenolar gider .
küçük giriş testi
seq 5 | sed -ne'2,3!w /tmp/L
s/.*/a-z &\& 0-9/p' >/tmp/F
... 5 satır numune girişi üretir. Sonra...
( export LC_ALL=C; </tmp/F \
grep -n '' | sort -t: -nmk1,1 ./L - |
sed /:/d\;n | cut -sd: -f2-
)| head - /tmp[FL]
... baskılar ...
==> 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
daha büyük zamanlı testler
Birkaç oldukça büyük dosya oluşturdum:
seq 5000000 | tee /tmp/F |
sort -R | head -n1500000 |
sort -n >/tmp/L
... ve 5mil satırları /tmp/F
ve 1.5mil rastgele seçilmiş satırları /tmp/L
. Sonra yaptım:
time \
( export LC_ALL=C
grep -n '' | sort -t: -nmk1,1 ./L - |
sed /:/d\;n | cut -sd: -f2-
) <./F |wc - l
Yazdırdı:
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
(Oraya ters eğik çizgi ekledim)
Şu anda burada sunulan çözümler arasında, bunların en hızlısıdır, ancak yukarıda makinemde üretilen veri kümesine karşı çekildiğinde bir tanesidir. Diğerleri arasından sadece biri ikinci sırada yer almaya yaklaştı ve bu da meuh'un perl
burada .
Bu hiçbir şekilde sunulan orijinal çözüm değildir - başkaları tarafından sunulan tavsiye / ilham sayesinde uygulama süresinin üçte birini düşürmüştür. Daha yavaş çözümler için gönderi geçmişine bakın (ama neden?) .
Ayrıca, sistemimin çoklu işlemci mimarisi ve bu boru hattındaki süreçlerin her birinin aynı anda yürütülmesi için değilse, diğer bazı cevapların çok daha iyi olabileceğini belirtmek gerekir. Hepsi aynı anda çalışır - her biri kendi işlemci çekirdeğinde - verilerin etrafında dolaşır ve bütünün küçük bir kısmını yapar. Oldukça havalı.
ama en hızlı çözüm ...
Ama en hızlı çözüm bu değil. Burada sunulan en hızlı çözüm, eller serbest, C programıdır . Aradım cselect
. X panomuza kopyaladıktan sonra şöyle derledim:
xsel -bo | cc -xc - -o cselect
Sonra yaptım:
time \
./cselect /tmp/L /tmp/F |
wc -l
... ve sonuçlar ...
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