我怎样才能快速汇总一个文件中的所有数字?
我有一个包含几千个数字的文件,每个数字都在它自己的行上:
34 42 11 6 2 99 ...
我正在寻找一个脚本,将打印文件中的所有数字的总和。 我有一个解决scheme,但效率不高。 (这需要几分钟的时间。)我正在寻找一个更有效的解决scheme。 有什么build议么?
对于Perl而言,它与Ayman Hourieh的答案中的awk
解决scheme基本相同:
% perl -nle '$sum += $_ } END { print $sum'
如果您好奇Perl单线程所做的事情,您可以对它们进行sorting:
% perl -MO=Deparse -nle '$sum += $_ } END { print $sum'
结果是一个更详细的程序版本,没有人会自己写:
BEGIN { $/ = "\n"; $\ = "\n"; } LINE: while (defined($_ = <ARGV>)) { chomp $_; $sum += $_; } sub END { print $sum; } -e syntax OK
只是为了咯咯地笑,我试着用一个包含1,000,000个数字的文件(范围在0 – 9,999)。 在我的Mac Pro上,它实际上即时返回。 这太糟糕了,因为我希望使用mmap
会非常快,但是它只是同一时间:
use 5.010; use File::Map qw(map_file); map_file my $map, $ARGV[0]; $sum += $1 while $map =~ m/(\d+)/g; say $sum;
你可以使用awk:
awk '{ sum += $1 } END { print sum }' file
只是为了好玩,让我们来衡量它:
$ for ((i=0; i<1000000; i++)) ; do echo $RANDOM; done > random_numbers $ time perl -nle '$sum += $_ } END { print $sum' random_numbers 16379866392 real 0m0.226s user 0m0.219s sys 0m0.002s $ time awk '{ sum += $1 } END { print sum }' random_numbers 16379866392 real 0m0.311s user 0m0.304s sys 0m0.005s $ time { { tr "\n" + < random_numbers ; echo 0; } | bc; } 16379866392 real 0m0.445s user 0m0.438s sys 0m0.024s $ time { s=0;while read l; do s=$((s+$l));done<random_numbers;echo $s; } 16379866392 real 0m9.309s user 0m8.404s sys 0m0.887s $ time { s=0;while read l; do ((s+=l));done<random_numbers;echo $s; } 16379866392 real 0m7.191s user 0m6.402s sys 0m0.776s $ time { sed ':a;N;s/\n/+/;ta' random_numbers|bc; } ^C real 4m53.413s user 4m52.584s sys 0m0.052s
5分钟后我中止了赛跑
迄今为止,解决scheme都没有使用paste
。 这里有一个:
paste -sd+ filename | bc
例如,计算Σn,其中1 <= n <= 100000:
$ seq 100000 | paste -sd+ | bc -l 5000050000
(为了好奇, seq n
会打印一个从1
到n
的数字序列,给定一个正数n
。)
这工作:
{ tr '\n' +; echo 0; } < file.txt | bc
另一个select是使用jq
:
$ seq 10|jq -s add 55
-s
(– --slurp
)将input行读入数组。
这是直Bash:
sum=0 while read -r line do (( sum += line )) done < file echo $sum
这是另外一个class轮
( echo 0 ; sed 's/$/ +/' foo ; echo p ) | dc
这假定这些数字是整数。 如果您需要小数点,请尝试
( echo 0 2k ; sed 's/$/ +/' foo ; echo p ) | dc
调整2到所需的小数位数。
cat nums | perl -ne '$sum += $_ } { print $sum'
(和brian d foy的答案一样,没有'END')
为了好玩,让我们用PDL ,Perl的数组math引擎来做吧!
perl -MPDL -E 'say rcols(shift)->sum' datafile
rcols
将列读入matrix(本例中为1D), sum
(惊奇)将matrix的所有元素相加。
这里是一个使用python和一个生成器expression式的解决scheme。 在我旧的笔记本电脑上testing了一百万个数字。
time python -c "import sys; print sum((float(l) for l in sys.stdin))" < file real 0m0.619s user 0m0.512s sys 0m0.028s
sed ':a;N;s/\n/+/;ta' file|bc
我更喜欢使用R这个:
$ R -e 'sum(scan("filename"))'
我不知道你是否可以比这更好,考虑到你需要通读整个文件。
$sum = 0; while(<>){ $sum += $_; } print $sum;
另一个乐趣
sum=0;for i in $(cat file);do sum=$((sum+$i));done;echo $sum
或者只是另一个bash
s=0;while read l; do s=$((s+$l));done<file;echo $s
但awk解决scheme可能是最好的,因为它是最紧凑的。
$ perl -MList::Util=sum -le 'print sum <>' nums.txt
用Ruby:
ruby -e "File.read('file.txt').split.inject(0){|mem, obj| mem += obj.to_f}"
更简洁:
# Ruby ruby -e 'puts open("random_numbers").map(&:to_i).reduce(:+)' # Python python -c 'print(sum(int(l) for l in open("random_numbers")))'
我更喜欢使用GNU datamash进行这样的任务,因为它比perl或awk更简洁明了。 例如
datamash sum 1 < myfile
其中1表示第一列数据。
这是另一个:
open(FIL, "a.txt"); my $sum = 0; foreach( <FIL> ) {chomp; $sum += $_;} close(FIL); print "Sum = $sum\n";
C总是赢得速度:
#include <stdio.h> #include <stdlib.h> int main(int argc, char **argv) { ssize_t read; char *line = NULL; size_t len = 0; double sum = 0.0; while (read = getline(&line, &len, stdin) != -1) { sum += atof(line); } printf("%f", sum); return 0; }
时间为1M数字(相同的机器/input作为我的Python的答案):
$ gcc sum.c -o sum && time ./sum < numbers 5003371677.000000 real 0m0.188s user 0m0.180s sys 0m0.000s
您可以使用Alacon – Alasql数据库的命令行实用程序。
它适用于Node.js,所以你需要安装Node.js ,然后安装Alasql包:
要从TXT文件计算总和,您可以使用以下命令:
> node alacon "SELECT VALUE SUM([0]) FROM TXT('mydata.txt')"
Perl 6
say sum lines
~$ perl6 -e '.say for 0..1000000' > test.in ~$ perl6 -e 'say sum lines' < test.in 500000500000
只是为了荒谬:
cat f | tr "\n" "+" | perl -pne chop | R --vanilla --slave
我没有testing过,但它应该工作:
cat f | tr "\n" "+" | sed 's/+$/\n/' | bc
如果bc不处理EOF和EOL,则可能必须在bc之前向string中添加“\ n”(如通过echo)。