sumas sumar resultado restas restar rapido que primer para niños mentalmente jugando grado formas enseñar den como aprendiendo aprender linux perl bash shell awk

linux - sumar - sumas que den como resultado 10



¿Cómo puedo sumar rápidamente todos los números en un archivo? (26)

Perl 6

say sum lines

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

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 suma 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?


¡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) suma todos los elementos de la matriz.


Aquí está otro:

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


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.


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


C siempre gana por velocidad:

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

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


Con Ruby:

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


Esto es derecho Bash:

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


Esto funciona:

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


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")))''


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


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


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


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

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


Otra opción es usar jq :

$ seq 10|jq -s add 55

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


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<file;echo $s

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


Para ser ridículo:

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


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 programa, en una forma que nadie podría escribir por sí mismo:

BEGIN { $/ = "/n"; $/ = "/n"; } LINE: while (defined($_ = <ARGV>)) { 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;


Prefiero usar R para esto:

$ R -e ''sum(scan("filename"))''


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.


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 suma del archivo TXT, puede usar el siguiente comando:

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


Puedes usar awk:

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


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

He abortado la carrera sed después de 5 minutos


$ perl -MList::Util=sum -le ''print sum <>'' nums.txt


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

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


sed '':a;N;s//n/+/;ta'' file|bc