¿Cómo puedo sumr rápidamente todos los números en un archivo?

Tengo un archivo que contiene varios miles de números, cada uno en su propia línea:

34 42 11 6 2 99 ... 

Estoy buscando escribir un script que imprima la sum de todos los números en el archivo. Tengo una solución, pero no es muy eficiente. (Toma varios minutos ejecutar). Estoy buscando una solución más eficiente. ¿Alguna sugerencia?

Para un Perl one-liner, es básicamente lo mismo que la solución awk en la respuesta de Ayman Hourieh :

  % perl -nle '$sum += $_ } END { print $sum' 

Si tiene curiosidad por saber qué es lo que hace una línea de Perl, puede detallarlos:

  % perl -MO=Deparse -nle '$sum += $_ } END { print $sum' 

El resultado es una versión más detallada del progtwig, en una forma que nadie podría escribir por sí mismo:

 BEGIN { $/ = "\n"; $\ = "\n"; } LINE: while (defined($_ = )) { chomp $_; $sum += $_; } sub END { print $sum; } -e syntax OK 

Solo por risitas, probé esto con un archivo que contiene 1,000,000 de números (en el rango 0 – 9,999). En mi Mac Pro, vuelve virtualmente de forma instantánea. Eso es muy malo, porque esperaba usar mmap sería muy rápido, pero es el mismo momento:

 use 5.010; use File::Map qw(map_file); map_file my $map, $ARGV[0]; $sum += $1 while $map =~ m/(\d+)/g; say $sum; 

Puedes usar awk:

 awk '{ sum += $1 } END { print sum }' file 

Ninguna de la solución hasta ahora usa paste . Aquí hay uno:

 paste -sd+ filename | bc 

Como ejemplo, calcule Σn donde 1 < = n <= 100000:

 $ seq 100000 | paste -sd+ | bc -l 5000050000 

(Para los curiosos, seq n imprimiría una secuencia de números del 1 al n dado un número positivo n .)

Solo por diversión, comparémoslo:

 $ 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 

He abortado la carrera sed después de 5 minutos

Esto funciona:

 { tr '\n' +; echo 0; } < file.txt | bc 

Otra opción es usar jq :

 $ seq 10|jq -s add 55 

-s ( --slurp ) lee las líneas de entrada en una matriz.

Esto es derecho Bash:

 sum=0 while read -r line do (( sum += line )) done < file echo $sum 

Aquí hay otro delineador

 ( echo 0 ; sed 's/$/ +/' foo ; echo p ) | dc 

Esto supone que los números son enteros. Si necesitas decimales, prueba

 ( echo 0 2k ; sed 's/$/ +/' foo ; echo p ) | dc 

Ajuste 2 a la cantidad de decimales necesarios.

Prefiero usar datamash de GNU para tales tareas porque es más breve y legible que Perl o Awk. Por ejemplo

 datamash sum 1 < myfile 

donde 1 denota la primera columna de datos.

 cat nums | perl -ne '$sum += $_ } { print $sum' 

(igual que la respuesta de Brian Foy, sin ‘FIN’)

¡Solo por diversión, hagámoslo con PDL , el motor matemático de matriz de Perl!

 perl -MPDL -E 'say rcols(shift)->sum' datafile 

rcols lee las columnas en una matriz (1D en este caso) y sum (sorpresa) sum todos los elementos de la matriz.

Aquí hay una solución que usa python con una expresión generadora. Probado con un millón de números en mi vieja computadora portátil.

 time python -c "import sys; print sum((float(l) for l in sys.stdin))" < file real 0m0.619s user 0m0.512s sys 0m0.028s 

Prefiero usar R para esto:

 $ R -e 'sum(scan("filename"))' 
 sed ':a;N;s/\n/+/;ta' file|bc 
 $ perl -MList::Util=sum -le 'print sum <>' nums.txt 

Perl 6

 say sum lines 
 ~$ perl6 -e '.say for 0..1000000' > test.in ~$ perl6 -e 'say sum lines' < test.in 500000500000 

Otra por diversión

 sum=0;for i in $(cat file);do sum=$((sum+$i));done;echo $sum 

u otro bash solamente

 s=0;while read l; do s=$((s+$l));done 

Pero la solución awk es probablemente la mejor ya que es más compacta.

Con Ruby:

 ruby -e "File.read('file.txt').split.inject(0){|mem, obj| mem += obj.to_f}" 

Más sucinto

 # Ruby ruby -e 'puts open("random_numbers").map(&:to_i).reduce(:+)' # Python python -c 'print(sum(int(l) for l in open("random_numbers")))' 

No sé si puede obtener mucho mejor que esto, teniendo en cuenta que necesita leer todo el archivo.

 $sum = 0; while(<>){ $sum += $_; } print $sum; 

No lo he probado, pero debería funcionar:

 cat f | tr "\n" "+" | sed 's/+$/\n/' | bc 

Es posible que tenga que agregar “\ n” a la cadena antes de bc (como a través de echo) si bc no trata EOF y EOL …

Aquí está otro:

 open(FIL, "a.txt"); my $sum = 0; foreach(  ) {chomp; $sum += $_;} close(FIL); print "Sum = $sum\n"; 

Puede hacerlo con Alacon – utilidad de línea de comandos para la base de datos Alasql .

Funciona con Node.js, por lo que necesita instalar Node.js y luego el paquete de Alasql :

Para calcular la sum del archivo TXT, puede usar el siguiente comando:

 > node alacon "SELECT VALUE SUM([0]) FROM TXT('mydata.txt')" 

No es más fácil reemplazar todas las líneas nuevas por + , agregar un 0 y enviarlo al intérprete de Ruby .

 (sed -e "s/$/+/" file; echo 0)|irb 

Si no tiene irb , puede enviarlo a bc , pero debe eliminar todas las líneas nuevas excepto la última (de echo ). Es mejor usar tr para esto, a menos que tengas un doctorado en sed .

 (sed -e "s/$/+/" file|tr -d "\n"; echo 0)|bc 

Para ser ridículo:

 cat f | tr "\n" "+" | perl -pne chop | R --vanilla --slave 

C siempre gana por velocidad:

 #include  #include  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; } 

Tiempo para números 1M (misma máquina / entrada que mi respuesta python):

 $ gcc sum.c -o sum && time ./sum < numbers 5003371677.000000 real 0m0.188s user 0m0.180s sys 0m0.000s