Bagaimana cara menghasilkan total kumulatif angka yang berjalan dalam file teks?

9

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?

Monty Harder
sumber
1
Dalam teks Anda, Anda mengatakan, bahwa Anda menginginkan tabel frekuensi . Sampel output Anda adalah daftar. Bisakah Anda menjelaskan ini?
Wayne_Yux
Memang output Anda bukan tabel frekuensi
don.joey
Maafkan saya. Maksud saya tabel frekuensi kumulatif. Telah memodifikasi pertanyaan. Terima kasih.
Ini tidak terlalu keren tapi saya biasanya hanya melakukan hal-hal seperti ini ke dalam spreadsheet.
John U
@ JohnU biasanya saya lakukan, tetapi file yang saya miliki memiliki 1 juta angka.

Jawaban:

20

Dengan awk:

awk '{total += $0; $0 = total}1'

$0adalah baris saat ini. Jadi, untuk setiap baris, saya menambahkannya ke total, setel baris ke yang baru total, dan kemudian trailing 1adalah jalan pintas awk - ini mencetak baris saat ini untuk setiap kondisi yang benar, dan 1ketika suatu kondisi mengevaluasi ke true.

muru
sumber
Bisakah Anda jelaskan kode Anda?
George Udosen
Bisakah kata printitu digunakan juga?
George Udosen
Ya,, print total}bukannya$0 = total}1
muru
1
@ Gee ah, tidak.
muru
9
Cara menulis naskah awk yang lebih pendek dan mungkin lebih mudah dipahami adalah{print(total += $0)}
Miles
9

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")

Menggunakan

  • Salin skrip ke file kosong, simpan sebagai add_last.py
  • Jalankan dengan file sumber dan file output yang ditargetkan sebagai argumen:

    python3 /path/to/add_last.py <input_file> <output_file>
    

Penjelasan

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")
    
Yakub Vlijm
sumber
3
Ini bukan tentang kekurangan atau kinerja waktu (juta baris bukan data besar). Kode dalam jawaban Anda bukan Python idiomatik. Jawaban saya adalah versi pythonic Anda.
jfs
8
@ JSFSebastian jika versi yang lebih idiomatis lebih lambat, mengapa ada yang lebih suka? Tidak ada yang istimewa tentang menjadi "pythonic" itu hanya sebuah konvensi yang membantu python devs berbagi kode dan standar untuk keterbacaan. Jika versi yang lebih idiomatis kurang efisien (lebih lambat) maka tidak boleh digunakan kecuali Anda bekerja di lingkungan di mana standardisasi lebih penting daripada kinerja (yang terdengar seperti ide yang mengerikan bagi saya).
terdon
2
@terdon ada sesuatu yang bisa dikatakan tentang optimasi prematur. Keterbacaan dapat menjadi penting karena pemeliharaan jangka panjang.
muru
4
@uru tentu saja, tapi ini bisa dibaca. Hanya saja kejahatan tidak menjadi "pythonic". Belum lagi kita berbicara tentang 7 baris kode, bukan proyek raksasa. Efisiensi pengorbanan atas nama konvensi gaya tampaknya merupakan pendekatan yang salah.
terdon
9

Hanya untuk bersenang-senang

$ sed 'a+p' file | dc -e0 -
3
7
12
20

Ini bekerja dengan sebuah ppending +puntuk setiap baris dari input, dan kemudian melewati hasilnya ke dckalkulator 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 -e0dorongan argumen 0ke dctumpukan untuk menginisialisasi jumlahnya.

Steeldriver
sumber
Sesuatu seperti ini mungkin sebenarnya yang tercepat dari dataset besar
Digital Trauma
@DigitalTrauma pada 1,3 juta baris, sebenarnya hampir paling lambat:real 0m4.234s
Jacob Vlijm
kesenangan adalah semua yang diperlukan untuk upvote: D aneh juga cukup: D: D
Rinzwind
Tolong jelaskan sedikit.
AmanicA
8

Di Bash:

#! /bin/bash

file="YOUR_FILE.txt"

TOTAL=0
while IFS= read -r line
do
    TOTAL=$(( TOTAL + line ))
    echo $TOTAL
done <"$file"
Julen Larrucea
sumber
bash sangat lambat dalam hal ini real 0m53.116s
:,
@JacobVlijm dasbor sekitar dua kali lebih cepat, busybox ash dan zsh (dalam mode sh) 1,5 kali, tetapi tentu saja, bahkan dasbor adalah 5 kali lebih lambat dari python.
muru
6

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)

Contoh runnable .

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

Contoh runnable .

UINTMAX_MAXadalah 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')
jfs
sumber
2
Mungkin juga layak menyebutkan accumulate()itertool
David Z
5

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 bagus

Contoh:
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
Wayne_Yux
sumber
Saya suka ini out put is nice:) ...
George Udosen
5

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.

James
sumber
1
1 untuk memecah mantra sihir dan menjelaskan semua bagian. Terlalu jarang di sekitar bagian-bagian ini.
John U
5

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
Sergiy Kolodyazhnyy
sumber
real 0m0.908scukup bagus
Jacob Vlijm
@JacobVlijm yang ada di file yang cukup kecil. Saya menambahkan tes kecil dengan 2,5 juta file baris. 6,64 detik
Sergiy Kolodyazhnyy
1
Saya menjalankan 1,3 juta baris pada sistem kuno
Jacob Vlijm
3

Bash one-liner sederhana:

x=0 ; while read n ; do x=$((x+n)) ; echo $x ; done < INPUT_FILE

xadalah jumlah terakumulasi dari semua angka dari baris saat ini dan di atas.
nadalah nomor di baris saat ini.

Kami loop atas semua baris ndari INPUT_FILEdan menambah nilai numerik mereka untuk variabel kami xdan 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).

Komandan Byte
sumber
3

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 sedekspresi mengubah input ke:

a+=3;a
a+=4;a
a+=5;a
a+=8;a

Ini kemudian dievaluasi oleh bc. The avariabel bc adalah auto-dijalankan ke 0. Setiap kenaikan garis a, maka secara eksplisit mencetaknya.

Trauma Digital
sumber
real 0m5.642spada 1,3 juta baris. Sed sangat lambat dalam hal ini.
Jacob Vlijm