ฉันจะสร้างจำนวนรวมสะสมในไฟล์ข้อความได้อย่างไร


9

ฉันมีไฟล์ข้อความที่มี 2 ล้านบรรทัด แต่ละบรรทัดมีจำนวนเต็มบวก ฉันกำลังพยายามสร้างตารางความถี่ชนิดของสิ่ง

ไฟล์อินพุต:

3
4
5
8

ผลลัพธ์ควรเป็น:

3
7
12
20

ฉันจะทำสิ่งนี้ได้อย่างไร


1
ในข้อความของคุณที่คุณพูดว่าคุณต้องการความถี่ตาราง ตัวอย่างผลลัพธ์ของคุณคือรายการ คุณช่วยอธิบายให้ฟังหน่อยได้ไหม?
Wayne_Yux

แน่นอนผลลัพธ์ของคุณไม่ใช่ตารางความถี่
don.joey

ฉันขอโทษ. ฉันหมายถึงตารางความถี่สะสม มีการปรับเปลี่ยนคำถาม ขอบคุณ

มันไม่เจ๋งนัก แต่ฉันมักทำแบบนี้ในสเปรดชีต
John U

@JohnU ฉันมักจะทำ แต่ไฟล์ที่ฉันมี 1 ล้านตัวเลข

คำตอบ:


20

ด้วยawk:

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

$0เป็นบรรทัดปัจจุบัน ดังนั้นสำหรับแต่ละบรรทัดฉันเพิ่มลงในtotalตั้งค่าบรรทัดเป็นใหม่totalจากนั้นส่วนท้าย1คือทางลัด awk - มันพิมพ์บรรทัดปัจจุบันสำหรับทุกเงื่อนไขจริงและ1ตามเงื่อนไขประเมินเป็นจริง


กรุณาอธิบายรหัสของคุณหน่อยได้ไหม?
George Udosen

สามารถใช้คำprintได้ด้วยหรือไม่
George Udosen

ใช่print total}แทนที่จะเป็น$0 = total}1
muru

1
@ George ah, no.
muru

9
วิธีที่สั้นและอาจเข้าใจได้มากกว่าในการเขียนสคริปต์ awk คือ{print(total += $0)}
Miles

9

ในสคริปต์หลาม:

#!/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
  • รันด้วยไฟล์ต้นฉบับและไฟล์เอาต์พุตเป้าหมายเป็นอาร์กิวเมนต์:

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

คำอธิบาย

รหัสค่อนข้างอ่านได้ แต่ในรายละเอียด:

  • เปิดไฟล์เอาต์พุตสำหรับการเขียนผลลัพธ์

    with open(out, "wt") as wr:
    
  • เปิดไฟล์อินพุตเพื่ออ่านต่อบรรทัด

    with open(f) as read:
        for l in read:
    
  • อ่านบรรทัดเพิ่มมูลค่าของบรรทัดใหม่ให้กับผลรวม:

    n = n + int(l)
    
  • เขียนผลลัพธ์ไปยังไฟล์เอาต์พุต:

    wr.write(str(n)+"\n")
    


3
มันไม่ได้เกี่ยวกับการย่อหรือประสิทธิภาพเวลา (ล้านเส้นไม่ใช่ข้อมูลขนาดใหญ่) รหัสในคำตอบของคุณไม่ใช่แบบ Python คำตอบของฉันคือรุ่น pythonic ของคุณ
jfs

8
@JFSebastian ถ้าเวอร์ชันที่ใช้สำนวนช้ากว่าทำไมใครถึงชอบมัน? ไม่มีอะไรพิเศษเกี่ยวกับการเป็น "pythonic" ที่เป็นเพียงการประชุมที่ช่วยให้หลาม devs แบ่งปันรหัสและมาตรฐานสำหรับการอ่าน หากเวอร์ชันที่ใช้สำนวนมีประสิทธิภาพน้อยกว่า (ช้ากว่า) ก็ไม่ควรใช้ถ้าคุณทำงานในสภาพแวดล้อมที่มาตรฐานมีความสำคัญมากกว่าประสิทธิภาพ (ซึ่งฟังดูเป็นความคิดที่น่ากลัวสำหรับฉัน)
terdon

2
@terdon มีบางอย่างที่ต้องพูดเกี่ยวกับการปรับให้เหมาะสมก่อนวัยอันควร ความสามารถในการอ่านอาจมีความสำคัญเนื่องจากการบำรุงรักษาในระยะยาว
muru

4
@muru แน่นอน แต่นี่อ่านได้อย่างสมบูรณ์ มีเพียงอาชญากรรมเท่านั้นที่ไม่ได้เป็น "pythonic" ไม่พูดถึงว่าเรากำลังพูดถึงโค้ด 7 บรรทัดไม่ใช่โครงการยักษ์ ประสิทธิภาพการเสียสละในชื่อของการประชุมสไตล์ดูเหมือนว่าวิธีการที่ผิด
terdon

9

แค่เล่น ๆ

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

นี้ทำงานโดยการppending แต่ละบรรทัดของการป้อนข้อมูลและจากนั้นผ่านผลไปยังเครื่องคิดเลขที่+pdc

   +      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.

แล้วก็

   p      Prints  the  value on the top of the stack, without altering the
          stack.  A newline is printed after the value.

-e0ดันอาร์กิวเมนต์0บนdcสแต็คในการเริ่มต้นรวม


สิ่งนี้อาจจะเร็วที่สุดในชุดข้อมูลขนาดใหญ่
Digital Trauma

@DigitalTrauma บน 1.3 ล้านเส้นจริงเกือบช้าที่สุด:real 0m4.234s
จาค็อบ Vlijm

ความสนุกคือสิ่งที่มันต้องการสำหรับการโหวต: D เล่นโวหารก็เพียงพอแล้วเช่นกัน: D: D
Rinzwind

โปรดอธิบายมันหน่อย
AmanicA

8

ใน 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เกือบนาทีใน 1.3 ล้านเส้น :)
จาค็อบ Vlijm

@JacobVlijm dash นั้นเร็วเป็นสองเท่า, busybox ash และ zsh (ในโหมด sh) 1.5 เท่า, แต่แน่นอน, แม้ dash จะช้ากว่าหลาม 5 เท่า.
muru

6

หากต้องการพิมพ์จำนวนเต็มบางส่วนของจำนวนเต็มที่กำหนดในอินพุตมาตรฐานหนึ่งรายการต่อบรรทัด:

#!/usr/bin/env python3
import sys

partial_sum = 0
for n in map(int, sys.stdin):
    partial_sum += n
    print(partial_sum)

ตัวอย่างที่เรียกใช้

ถ้าด้วยเหตุผลบางอย่างคำสั่งช้าเกินไป; คุณสามารถใช้โปรแกรม 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;
}

หากต้องการสร้างและเรียกใช้ให้พิมพ์:

$ cc cumsum.c -o cumsum
$ ./cumsum < input > output

ตัวอย่างที่เรียกใช้

UINTMAX_MAX18446744073709551615เป็น

รหัส C เร็วกว่าคำสั่ง awk หลายเท่าในเครื่องสำหรับไฟล์อินพุตที่สร้างโดย:

#!/usr/bin/env python3
import numpy.random
print(*numpy.random.random_integers(100, size=2000000), sep='\n')

2
มันอาจจะคุ้มค่าที่จะกล่าวถึงaccumulate()itertool
David Z

5

คุณอาจต้องการสิ่งนี้:

sort -n <filename> | uniq -c | awk 'BEGIN{print "Number\tFrequency"}{print $2"\t"$1}'

คำอธิบายของคำสั่ง:

  • sort -n <filename> | uniq -c เรียงลำดับอินพุตและส่งคืนตารางความถี่
  • | awk 'BEGIN{print "Number\tFrequency"}{print $2"\t"$1}' เปลี่ยน ooutput ให้เป็นรูปแบบที่ดีกว่า

ตัวอย่าง:
ไฟล์อินพุตlist.txt:

4
5
3
4
4
2
3
4
5

คำสั่ง:

$ 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

ฉันชอบสิ่งนี้การออกแบบที่ดี
:)

5

คุณสามารถทำได้ในกลุ่ม เปิดไฟล์และพิมพ์การกดแป้นต่อไปนี้:

qaqqayiwj@"<C-a>@aq@a:wq<cr>

โปรดทราบว่า<C-a>จริง ๆ แล้วคือ ctrl-a และ<cr>เป็นcarriage returnเช่นปุ่ม Enter

นี่คือวิธีการทำงาน ก่อนอื่นเราต้องการลบการลงทะเบียน 'a' เพื่อไม่ให้มีผลข้างเคียงในครั้งแรกที่ผ่านไป qaqนี้เป็นเพียง จากนั้นเราจะทำสิ่งต่อไปนี้:

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

หลังจากเรียกใช้แมโครแบบเรียกซ้ำนี้เสร็จแล้วเราเพียงเรียก:wq<cr>เพื่อบันทึกและออก


1
+1 สำหรับการทำลายคาถาเวทมนตร์และอธิบายชิ้นส่วนทั้งหมด ส่วนเหล่านี้หายากเกินไป
John U

5

Perl หนึ่งซับ:

$ perl -lne 'print $sum+=$_' input.txt                                                                
3
7
12
20

ด้วยตัวเลข 2.5 ล้านบรรทัดใช้เวลาประมวลผลประมาณ 6.6 วินาที:

$ 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ค่อนข้างดี
Jacob Vlijm

@JacobVlijm ที่อยู่ในไฟล์ขนาดเล็กสวย ฉันเพิ่มการทดสอบขนาดเล็กที่มีไฟล์ 2.5 ล้านบรรทัด 6.64 วินาที
Sergiy Kolodyazhnyy

1
ฉันวิ่ง 1.3 ล้านบรรทัดบนระบบโบราณ
Jacob Vlijm

3

Bash หนึ่งซับง่าย ๆ :

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

xคือผลรวมสะสมของตัวเลขทั้งหมดจากบรรทัดปัจจุบันและสูงกว่า
nคือตัวเลขในบรรทัดปัจจุบัน

เราห่วงมากกว่าทุกสายnของINPUT_FILEและเพิ่มค่าตัวเลขของพวกเขาให้กับตัวแปรของเราxและพิมพ์ผลรวมว่าในช่วงแต่ละซ้ำ

Bash ค่อนข้างช้าที่นี่คุณสามารถคาดหวังว่าไฟล์นี้จะทำงานประมาณ 20-30 วินาทีสำหรับไฟล์ที่มี 2 ล้านรายการโดยไม่ต้องพิมพ์เอาต์พุตไปยังคอนโซล (ซึ่งช้ากว่าเป็นอิสระจากวิธีการที่คุณใช้)


3

คล้ายกับคำตอบของ @ steeldriver แต่มีความลับน้อยกว่าbcแทน:

sed 's/.*/a+=&;a/' input | bc

สิ่งที่ดีเกี่ยวกับbc(และdc) คือพวกมันเป็นเครื่องคิดเลขที่มีความแม่นยำตามอำเภอใจดังนั้นจะไม่มีวันล้นหรือไม่มีความแม่นยำของจำนวนเต็ม

sedแสดงออกแปลงการป้อนข้อมูลเพื่อ:

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

bcนี้ได้รับการประเมินแล้วโดย aตัวแปร BC เป็นอัตโนมัติ initialised 0 เพิ่มขึ้นแต่ละบรรทัดaแล้วอย่างชัดเจนพิมพ์มัน


real 0m5.642sบน 1.3 ล้านบรรทัด sed ช้ามากในเรื่องนี้
Jacob Vlijm
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.