Mar*_*rts 178 linux bash shell perl awk
我有一个包含数千个数字的文件,每个数字都在它自己的行上:
34
42
11
6
2
99
...
Run Code Online (Sandbox Code Playgroud)
我正在寻找一个脚本,它将打印文件中所有数字的总和.我有一个解决方案,但效率不高.(运行需要几分钟.)我正在寻找更有效的解决方案.有什么建议?
Aym*_*ieh 350
你可以使用awk:
awk '{ sum += $1 } END { print sum }' file
Run Code Online (Sandbox Code Playgroud)
bri*_*foy 105
对于Perl 单线程,它与Ayman Hourieh的答案中的awk解决方案基本相同:
% perl -nle '$sum += $_ } END { print $sum'
Run Code Online (Sandbox Code Playgroud)
如果您对Perl单行所做的很好奇,您可以解析它们:
% perl -MO=Deparse -nle '$sum += $_ } END { print $sum'
Run Code Online (Sandbox Code Playgroud)
结果是一个更冗长的程序版本,其形式是任何人都不会自己写的:
BEGIN { $/ = "\n"; $\ = "\n"; }
LINE: while (defined($_ = <ARGV>)) {
chomp $_;
$sum += $_;
}
sub END {
print $sum;
}
-e syntax OK
Run Code Online (Sandbox Code Playgroud)
只是为了咯咯笑,我试着用一个包含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;
Run Code Online (Sandbox Code Playgroud)
dev*_*ull 93
迄今为止没有一种解决方案paste.这是一个:
paste -sd+ filename | bc
Run Code Online (Sandbox Code Playgroud)
例如,计算Σn,其中1 <= n <= 100000:
$ seq 100000 | paste -sd+ | bc -l
5000050000
Run Code Online (Sandbox Code Playgroud)
(对于好奇的人,seq n会打印一系列数字1,n给出一个正数n.)
gle*_*man 80
只是为了好玩,让我们对它进行基准测试:
$ 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
Run Code Online (Sandbox Code Playgroud)
我在5分钟后中止了sed运行
nis*_*ama 16
另一种选择是使用jq:
$ seq 10|jq -s add
55
Run Code Online (Sandbox Code Playgroud)
-s(--slurp)将输入行读入数组.
这是直接的Bash:
sum=0
while read -r line
do
(( sum += line ))
done < file
echo $sum
Run Code Online (Sandbox Code Playgroud)
这是另一个单行
( echo 0 ; sed 's/$/ +/' foo ; echo p ) | dc
Run Code Online (Sandbox Code Playgroud)
这假设数字是整数.如果您需要小数,请尝试
( echo 0 2k ; sed 's/$/ +/' foo ; echo p ) | dc
Run Code Online (Sandbox Code Playgroud)
将2调整为所需的小数位数.
我更喜欢将 GNU datamash 用于此类任务,因为它比 perl 或 awk 更简洁易读。例如
datamash sum 1 < myfile
Run Code Online (Sandbox Code Playgroud)
其中 1 表示第一列数据。
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\n", sum);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
1M 数字的计时(与我的 python 答案相同的机器/输入):
$ gcc sum.c -o sum && time ./sum < numbers
5003371677.000000
real 0m0.188s
user 0m0.180s
sys 0m0.000s
Run Code Online (Sandbox Code Playgroud)
更简洁:
# Ruby
ruby -e 'puts open("random_numbers").map(&:to_i).reduce(:+)'
# Python
python -c 'print(sum(int(l) for l in open("random_numbers")))'
Run Code Online (Sandbox Code Playgroud)
say sum lines
Run Code Online (Sandbox Code Playgroud)
~$ perl6 -e '.say for 0..1000000' > test.in
~$ perl6 -e 'say sum lines' < test.in
500000500000
Run Code Online (Sandbox Code Playgroud)
我不能就这么过去……这是我的哈斯克尔俏皮话。它实际上非常可读:
sum <$> (read <$>) <$> lines <$> getContents
Run Code Online (Sandbox Code Playgroud)
不幸的是,没有办法ghci -e直接运行它,所以它需要 main 函数、打印和编译。
main = (sum <$> (read <$>) <$> lines <$> getContents) >>= print
Run Code Online (Sandbox Code Playgroud)
为了澄清起见,我们读取整个输入 ( getContents),将其分割为lines,read作为数字 和sum。<$>isfmap运算符 - 我们使用它而不是通常的函数应用程序,因为这一切都发生在 IO 中。read需要一个额外的fmap,因为它也在列表中。
$ ghc sum.hs
[1 of 1] Compiling Main ( sum.hs, sum.o )
Linking sum ...
$ ./sum
1
2
4
^D
7
Run Code Online (Sandbox Code Playgroud)
这是一个奇怪的升级,使其可以与浮动一起使用:
main = ((0.0 + ) <$> sum <$> (read <$>) <$> lines <$> getContents) >>= print
Run Code Online (Sandbox Code Playgroud)
$ ./sum
1.3
2.1
4.2
^D
7.6000000000000005
Run Code Online (Sandbox Code Playgroud)