ฉันมีไฟล์ข้อความที่มี 2 ล้านบรรทัด แต่ละบรรทัดมีจำนวนเต็มบวก ฉันกำลังพยายามสร้างตารางความถี่ชนิดของสิ่ง
ไฟล์อินพุต:
3
4
5
8
ผลลัพธ์ควรเป็น:
3
7
12
20
ฉันจะทำสิ่งนี้ได้อย่างไร
ฉันมีไฟล์ข้อความที่มี 2 ล้านบรรทัด แต่ละบรรทัดมีจำนวนเต็มบวก ฉันกำลังพยายามสร้างตารางความถี่ชนิดของสิ่ง
ไฟล์อินพุต:
3
4
5
8
ผลลัพธ์ควรเป็น:
3
7
12
20
ฉันจะทำสิ่งนี้ได้อย่างไร
คำตอบ:
ด้วยawk
:
awk '{total += $0; $0 = total}1'
$0
เป็นบรรทัดปัจจุบัน ดังนั้นสำหรับแต่ละบรรทัดฉันเพิ่มลงในtotal
ตั้งค่าบรรทัดเป็นใหม่total
จากนั้นส่วนท้าย1
คือทางลัด awk - มันพิมพ์บรรทัดปัจจุบันสำหรับทุกเงื่อนไขจริงและ1
ตามเงื่อนไขประเมินเป็นจริง
print
ได้ด้วยหรือไม่
print total}
แทนที่จะเป็น$0 = total}1
{print(total += $0)}
ในสคริปต์หลาม:
#!/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")
แค่เล่น ๆ
$ sed 'a+p' file | dc -e0 -
3
7
12
20
นี้ทำงานโดยการppending แต่ละบรรทัดของการป้อนข้อมูลและจากนั้นผ่านผลไปยังเครื่องคิดเลขที่+p
dc
+ 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
สแต็คในการเริ่มต้นรวม
real 0m4.234s
ใน 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 ล้านเส้น :)
หากต้องการพิมพ์จำนวนเต็มบางส่วนของจำนวนเต็มที่กำหนดในอินพุตมาตรฐานหนึ่งรายการต่อบรรทัด:
#!/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_MAX
18446744073709551615
เป็น
รหัส C เร็วกว่าคำสั่ง awk หลายเท่าในเครื่องสำหรับไฟล์อินพุตที่สร้างโดย:
#!/usr/bin/env python3
import numpy.random
print(*numpy.random.random_integers(100, size=2000000), sep='\n')
accumulate()
itertool
คุณอาจต้องการสิ่งนี้:
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
คุณสามารถทำได้ในกลุ่ม เปิดไฟล์และพิมพ์การกดแป้นต่อไปนี้:
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>
เพื่อบันทึกและออก
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
ค่อนข้างดี
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 ล้านรายการโดยไม่ต้องพิมพ์เอาต์พุตไปยังคอนโซล (ซึ่งช้ากว่าเป็นอิสระจากวิธีการที่คุณใช้)
คล้ายกับคำตอบของ @ 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 ช้ามากในเรื่องนี้