Saya memiliki file teks dengan 2 juta baris. Setiap baris memiliki bilangan bulat positif. Saya mencoba untuk membentuk semacam tabel frekuensi hal.
File input:
3
4
5
8
Output harus:
3
7
12
20
Bagaimana cara saya melakukan ini?
Saya memiliki file teks dengan 2 juta baris. Setiap baris memiliki bilangan bulat positif. Saya mencoba untuk membentuk semacam tabel frekuensi hal.
File input:
3
4
5
8
Output harus:
3
7
12
20
Bagaimana cara saya melakukan ini?
Jawaban:
Dengan awk
:
awk '{total += $0; $0 = total}1'
$0
adalah baris saat ini. Jadi, untuk setiap baris, saya menambahkannya ke total
, setel baris ke yang baru total
, dan kemudian trailing 1
adalah jalan pintas awk - ini mencetak baris saat ini untuk setiap kondisi yang benar, dan 1
ketika suatu kondisi mengevaluasi ke true.
print
itu digunakan juga?
print total}
bukannya$0 = total}1
{print(total += $0)}
Dalam skrip python:
#!/usr/bin/env python3
import sys
f = sys.argv[1]; out = sys.argv[2]
n = 0
with open(out, "wt") as wr:
with open(f) as read:
for l in read:
n = n + int(l); wr.write(str(n)+"\n")
add_last.py
Jalankan dengan file sumber dan file output yang ditargetkan sebagai argumen:
python3 /path/to/add_last.py <input_file> <output_file>
Kode ini agak mudah dibaca, tetapi secara detail:
Buka file output untuk menulis hasil
with open(out, "wt") as wr:
Buka file input untuk dibaca per baris
with open(f) as read:
for l in read:
Baca baris, tambahkan nilai baris baru ke total:
n = n + int(l)
Tulis hasilnya ke file output:
wr.write(str(n)+"\n")
Hanya untuk bersenang-senang
$ sed 'a+p' file | dc -e0 -
3
7
12
20
Ini bekerja dengan sebuah ppending +p
untuk setiap baris dari input, dan kemudian melewati hasilnya ke dc
kalkulator mana
+ Pops two values off the stack, adds them, and pushes the result.
The precision of the result is determined only by the values of
the arguments, and is enough to be exact.
kemudian
p Prints the value on the top of the stack, without altering the
stack. A newline is printed after the value.
The -e0
dorongan argumen 0
ke dc
tumpukan untuk menginisialisasi jumlahnya.
real 0m4.234s
Di Bash:
#! /bin/bash
file="YOUR_FILE.txt"
TOTAL=0
while IFS= read -r line
do
TOTAL=$(( TOTAL + line ))
echo $TOTAL
done <"$file"
real 0m53.116s
Untuk mencetak sebagian jumlah bilangan bulat yang diberikan pada input standar satu per baris:
#!/usr/bin/env python3
import sys
partial_sum = 0
for n in map(int, sys.stdin):
partial_sum += n
print(partial_sum)
Jika karena alasan tertentu perintahnya terlalu lambat; Anda bisa menggunakan program C:
#include <stdint.h>
#include <ctype.h>
#include <stdio.h>
int main(void)
{
uintmax_t cumsum = 0, n = 0;
for (int c = EOF; (c = getchar()) != EOF; ) {
if (isdigit(c))
n = n * 10 + (c - '0');
else if (n) { // complete number
cumsum += n;
printf("%ju\n", cumsum);
n = 0;
}
}
if (n)
printf("%ju\n", cumsum + n);
return feof(stdin) ? 0 : 1;
}
Untuk membangun dan menjalankannya, ketik:
$ cc cumsum.c -o cumsum
$ ./cumsum < input > output
UINTMAX_MAX
adalah 18446744073709551615
.
Kode C beberapa kali lebih cepat daripada perintah awk pada mesin saya untuk file input yang dihasilkan oleh:
#!/usr/bin/env python3
import numpy.random
print(*numpy.random.random_integers(100, size=2000000), sep='\n')
accumulate()
itertool
Anda mungkin menginginkan sesuatu seperti ini:
sort -n <filename> | uniq -c | awk 'BEGIN{print "Number\tFrequency"}{print $2"\t"$1}'
Penjelasan perintah:
sort -n <filename> | uniq -c
mengurutkan input dan mengembalikan tabel frekuensi| awk 'BEGIN{print "Number\tFrequency"}{print $2"\t"$1}'
mengubah ooutput menjadi Format yang lebih bagusContoh:
File Input list.txt
:
4
5
3
4
4
2
3
4
5
Perintah:
$ sort -n list.txt | uniq -c | awk 'BEGIN{print "Number\tFrequency"}{print $2"\t"$1}'
Number Frequency
2 1
3 2
4 4
5 2
Anda dapat melakukan ini di vim. Buka file dan ketik penekanan tombol berikut:
qaqqayiwj@"<C-a>@aq@a:wq<cr>
Perhatikan bahwa <C-a>
sebenarnya ctrl-a, dan <cr>
merupakan carriage return , yaitu tombol enter.
Begini cara kerjanya. Pertama, kami ingin menghapus register 'a' sehingga tidak memiliki efek samping pada saat pertama kali melalui. Ini sederhana qaq
. Kemudian kita lakukan hal berikut:
qa " Start recording keystrokes into register 'a'
yiw " Yank this current number
j " Move down one line. This will break the loop on the last line
@" " Run the number we yanked as if it was typed, and then
<C-a> " increment the number under the cursor *n* times
@a " Call macro 'a'. While recording this will do nothing
q " Stop recording
@a " Call macro 'a', which will call itself creating a loop
Setelah makro rekursif ini selesai berjalan, kami cukup memanggil :wq<cr>
untuk menyimpan dan keluar.
Perl one-liner:
$ perl -lne 'print $sum+=$_' input.txt
3
7
12
20
Dengan 2,5 juta baris angka, dibutuhkan proses sekitar 6,6 detik:
$ time perl -lne 'print $sum+=$_' large_input.txt > output.txt
0m06.64s real 0m05.42s user 0m00.09s system
$ wc -l large_input.txt
2500000 large_input.txt
real 0m0.908s
cukup bagus
Bash one-liner sederhana:
x=0 ; while read n ; do x=$((x+n)) ; echo $x ; done < INPUT_FILE
x
adalah jumlah terakumulasi dari semua angka dari baris saat ini dan di atas.
n
adalah nomor di baris saat ini.
Kami loop atas semua baris n
dari INPUT_FILE
dan menambah nilai numerik mereka untuk variabel kami x
dan mencetak jumlah itu selama setiap iterasi.
Namun, Bash agak lambat di sini, Anda bisa berharap ini berjalan sekitar 20-30 detik untuk file dengan 2 juta entri, tanpa mencetak output ke konsol (yang bahkan lebih lambat, tidak tergantung pada metode yang Anda gunakan).
Mirip dengan jawaban @ steeldriver, tetapi dengan sedikit lebih misterius bc
:
sed 's/.*/a+=&;a/' input | bc
Yang menyenangkan tentang bc
(dan dc
) adalah bahwa mereka adalah kalkulator presisi yang sewenang-wenang, jadi tidak akan pernah meluap atau mengalami kekurangan presisi atas bilangan bulat.
The sed
ekspresi mengubah input ke:
a+=3;a
a+=4;a
a+=5;a
a+=8;a
Ini kemudian dievaluasi oleh bc
. The a
variabel bc adalah auto-dijalankan ke 0. Setiap kenaikan garis a
, maka secara eksplisit mencetaknya.
real 0m5.642s
pada 1,3 juta baris. Sed sangat lambat dalam hal ini.