Automágica: durante 2017 estoy trabajando bastante en Automágica, mi software para editar libros: Más información - Posts relacionados

Ejercicio 16 - proyecto Euler

De vez en cuando se me da por hacer saries de posts en el blog. Sagas. Una de las últimas fue la saga sobre resoluciones a problemas del proyecto Euler. Lo que intentaba era resolverlos con alguna característica interesante de Python y luego explicarla. Luego de los primeros, los ejercisios se volvieron más matemáticos y encontraba menos cosas interesantes de Python que comentar, así que dejé de postear mis soluciones. Acabo de encontrar esta entre mis archivos y creo que tiene algo de originalidad como para merecer ser publicada:

¿Cuál es la suma de los dígitos del número 2^(1000)?

>>> 2**1000

107150860718626732094842504906000[algunos números fueron intencionalmente borrados]

>>> a = 2**1000

>>> sum((int(x) for x in list(str(a))))

1366

¿A alguien se le ocurre otra forma?


Euler 8 (Python)

Enunciado 8

Encontrar el mayor producto de cinco dígitos consecutivos en este número de 100 dígitos:

73167176531330624919225119674426574742355349194934 96983520312774506326239578318016984801869478851843 85861560789112949495459501737958331952853208805511 12540698747158523863050715693290963295227443043557 66896648950445244523161731856403098711121722383113 62229893423380308135336276614282806444486645238749 30358907296290491560440772390713810515859307960866 70172427121883998797908792274921901699720888093776 65727333001053367881220235421809751254540594752243 52584907711670556013604839586446706324415722155397 53697817977846174064955149290862569321978468622482 83972241375657056057490261407972968652414535100474 82166370484403199890008895243450658541227588666881 16427171479924442928230863465674813919123162824586 17866458359124566529476545682848912883142607690042 24219022671055626321111109370544217506941658960408 07198403850962455444362981230987879927244284909188 84580156166097919133875499200524063689912560717606 05886116467109405077541002256983155200055935729725 71636269561882670428252483600823257530420752963450

Solución

>>> b = 7316717653133062491922511967442657474235534919493496983520312774506326239578318016984801869478851843858615607891129494954595017379583319528532088055111254069874715852386305071569329096329522744304355766896648950445244523161731856403098711121722383113622298934233803081353362766142828064444866452387493035890729629049156044077239071381051585930796086670172427121883998797908792274921901699720888093776657273330010533678812202354218097512545405947522435258490771167055601360483958644670632441572215539753697817977846174064955149290862569321978468622482839722413756570560574902614079729686524145351004748216637048440319989000889524345065854122758866688116427171479924442928230863465674813919123162824586178664583591245665294765456828489128831426076900422421902267105562632111110937054421750694165896040807198403850962455444362981230987879927244284909188845801561660979191338754992005240636899125607176060588611646710940507754100225698315520005593572972571636269561882670428252483600823257530420752963450

>>> s = str(b)

>>> s

'7316717653133062491922511967442657474235534919493496983520312774506326239578318016984801869478851843858615607891129494954595017379583319528532088055111254069874715852386305071569329096329522744304355766896648950445244523161731856403098711121722383113622298934233803081353362766142828064444866452387493035890729629049156044077239071381051585930796086670172427121883998797908792274921901699720888093776657273330010533678812202354218097512545405947522435258490771167055601360483958644670632441572215539753697817977846174064955149290862569321978468622482839722413756570560574902614079729686524145351004748216637048440319989000889524345065854122758866688116427171479924442928230863465674813919123162824586178664583591245665294765456828489128831426076900422421902267105562632111110937054421750694165896040807198403850962455444362981230987879927244284909188845801561660979191338754992005240636899125607176060588611646710940507754100225698315520005593572972571636269561882670428252483600823257530420752963450'

>>> l = list(s)

>>> l

['7', '3', '1', '6', '7', '1', '7', '6', '5', '3', '1', '3', '3', '0', '6', '2', '4', '9', '1', '9', '2', '2', '5', '1', '1', '9', '6', '7', '4', '4', '2', '6', '5', '7', '4', '7', '4', '2', '3', '5', '5', '3', '4', '9', '1', '9', '4', '9', '3', '4', '9', '6', '9', '8', '3', '5', '2', '0', '3', '1', '2', '7', '7', '4', '5', '0', '6', '3', '2', '6', '2', '3', '9', '5', '7', '8', '3', '1', '8', '0', '1', '6', '9', '8', '4', '8', '0', '1', '8', '6', '9', '4', '7', '8', '8', '5', '1', '8', '4', '3', '8', '5', '8', '6', '1', '5', '6', '0', '7', '8', '9', '1', '1', '2', '9', '4', '9', '4', '9', '5', '4', '5', '9', '5', '0', '1', '7', '3', '7', '9', '5', '8', '3', '3', '1', '9', '5', '2', '8', '5', '3', '2', '0', '8', '8', '0', '5', '5', '1', '1', '1', '2', '5', '4', '0', '6', '9', '8', '7', '4', '7', '1', '5', '8', '5', '2', '3', '8', '6', '3', '0', '5', '0', '7', '1', '5', '6', '9', '3', '2', '9', '0', '9', '6', '3', '2', '9', '5', '2', '2', '7', '4', '4', '3', '0', '4', '3', '5', '5', '7', '6', '6', '8', '9', '6', '6', '4', '8', '9', '5', '0', '4', '4', '5', '2', '4', '4', '5', '2', '3', '1', '6', '1', '7', '3', '1', '8', '5', '6', '4', '0', '3', '0', '9', '8', '7', '1', '1', '1', '2', '1', '7', '2', '2', '3', '8', '3', '1', '1', '3', '6', '2', '2', '2', '9', '8', '9', '3', '4', '2', '3', '3', '8', '0', '3', '0', '8', '1', '3', '5', '3', '3', '6', '2', '7', '6', '6', '1', '4', '2', '8', '2', '8', '0', '6', '4', '4', '4', '4', '8', '6', '6', '4', '5', '2', '3', '8', '7', '4', '9', '3', '0', '3', '5', '8', '9', '0', '7', '2', '9', '6', '2', '9', '0', '4', '9', '1', '5', '6', '0', '4', '4', '0', '7', '7', '2', '3', '9', '0', '7', '1', '3', '8', '1', '0', '5', '1', '5', '8', '5', '9', '3', '0', '7', '9', '6', '0', '8', '6', '6', '7', '0', '1', '7', '2', '4', '2', '7', '1', '2', '1', '8', '8', '3', '9', '9', '8', '7', '9', '7', '9', '0', '8', '7', '9', '2', '2', '7', '4', '9', '2', '1', '9', '0', '1', '6', '9', '9', '7', '2', '0', '8', '8', '8', '0', '9', '3', '7', '7', '6', '6', '5', '7', '2', '7', '3', '3', '3', '0', '0', '1', '0', '5', '3', '3', '6', '7', '8', '8', '1', '2', '2', '0', '2', '3', '5', '4', '2', '1', '8', '0', '9', '7', '5', '1', '2', '5', '4', '5', '4', '0', '5', '9', '4', '7', '5', '2', '2', '4', '3', '5', '2', '5', '8', '4', '9', '0', '7', '7', '1', '1', '6', '7', '0', '5', '5', '6', '0', '1', '3', '6', '0', '4', '8', '3', '9', '5', '8', '6', '4', '4', '6', '7', '0', '6', '3', '2', '4', '4', '1', '5', '7', '2', '2', '1', '5', '5', '3', '9', '7', '5', '3', '6', '9', '7', '8', '1', '7', '9', '7', '7', '8', '4', '6', '1', '7', '4', '0', '6', '4', '9', '5', '5', '1', '4', '9', '2', '9', '0', '8', '6', '2', '5', '6', '9', '3', '2', '1', '9', '7', '8', '4', '6', '8', '6', '2', '2', '4', '8', '2', '8', '3', '9', '7', '2', '2', '4', '1', '3', '7', '5', '6', '5', '7', '0', '5', '6', '0', '5', '7', '4', '9', '0', '2', '6', '1', '4', '0', '7', '9', '7', '2', '9', '6', '8', '6', '5', '2', '4', '1', '4', '5', '3', '5', '1', '0', '0', '4', '7', '4', '8', '2', '1', '6', '6', '3', '7', '0', '4', '8', '4', '4', '0', '3', '1', '9', '9', '8', '9', '0', '0', '0', '8', '8', '9', '5', '2', '4', '3', '4', '5', '0', '6', '5', '8', '5', '4', '1', '2', '2', '7', '5', '8', '8', '6', '6', '6', '8', '8', '1', '1', '6', '4', '2', '7', '1', '7', '1', '4', '7', '9', '9', '2', '4', '4', '4', '2', '9', '2', '8', '2', '3', '0', '8', '6', '3', '4', '6', '5', '6', '7', '4', '8', '1', '3', '9', '1', '9', '1', '2', '3', '1', '6', '2', '8', '2', '4', '5', '8', '6', '1', '7', '8', '6', '6', '4', '5', '8', '3', '5', '9', '1', '2', '4', '5', '6', '6', '5', '2', '9', '4', '7', '6', '5', '4', '5', '6', '8', '2', '8', '4', '8', '9', '1', '2', '8', '8', '3', '1', '4', '2', '6', '0', '7', '6', '9', '0', '0', '4', '2', '2', '4', '2', '1', '9', '0', '2', '2', '6', '7', '1', '0', '5', '5', '6', '2', '6', '3', '2', '1', '1', '1', '1', '1', '0', '9', '3', '7', '0', '5', '4', '4', '2', '1', '7', '5', '0', '6', '9', '4', '1', '6', '5', '8', '9', '6', '0', '4', '0', '8', '0', '7', '1', '9', '8', '4', '0', '3', '8', '5', '0', '9', '6', '2', '4', '5', '5', '4', '4', '4', '3', '6', '2', '9', '8', '1', '2', '3', '0', '9', '8', '7', '8', '7', '9', '9', '2', '7', '2', '4', '4', '2', '8', '4', '9', '0', '9', '1', '8', '8', '8', '4', '5', '8', '0', '1', '5', '6', '1', '6', '6', '0', '9', '7', '9', '1', '9', '1', '3', '3', '8', '7', '5', '4', '9', '9', '2', '0', '0', '5', '2', '4', '0', '6', '3', '6', '8', '9', '9', '1', '2', '5', '6', '0', '7', '1', '7', '6', '0', '6', '0', '5', '8', '8', '6', '1', '1', '6', '4', '6', '7', '1', '0', '9', '4', '0', '5', '0', '7', '7', '5', '4', '1', '0', '0', '2', '2', '5', '6', '9', '8', '3', '1', '5', '5', '2', '0', '0', '0', '5', '5', '9', '3', '5', '7', '2', '9', '7', '2', '5', '7', '1', '6', '3', '6', '2', '6', '9', '5', '6', '1', '8', '8', '2', '6', '7', '0', '4', '2', '8', '2', '5', '2', '4', '8', '3', '6', '0', '0', '8', '2', '3', '2', '5', '7', '5', '3', '0', '4', '2', '0', '7', '5', '2', '9', '6', '3', '4', '5', '0']

>>> i = [int(x) for x in l]

>>> i

[7, 3, 1, 6, 7, 1, 7, 6, 5, 3, 1, 3, 3, 0, 6, 2, 4, 9, 1, 9, 2, 2, 5, 1, 1, 9, 6, 7, 4, 4, 2, 6, 5, 7, 4, 7, 4, 2, 3, 5, 5, 3, 4, 9, 1, 9, 4, 9, 3, 4, 9, 6, 9, 8, 3, 5, 2, 0, 3, 1, 2, 7, 7, 4, 5, 0, 6, 3, 2, 6, 2, 3, 9, 5, 7, 8, 3, 1, 8, 0, 1, 6, 9, 8, 4, 8, 0, 1, 8, 6, 9, 4, 7, 8, 8, 5, 1, 8, 4, 3, 8, 5, 8, 6, 1, 5, 6, 0, 7, 8, 9, 1, 1, 2, 9, 4, 9, 4, 9, 5, 4, 5, 9, 5, 0, 1, 7, 3, 7, 9, 5, 8, 3, 3, 1, 9, 5, 2, 8, 5, 3, 2, 0, 8, 8, 0, 5, 5, 1, 1, 1, 2, 5, 4, 0, 6, 9, 8, 7, 4, 7, 1, 5, 8, 5, 2, 3, 8, 6, 3, 0, 5, 0, 7, 1, 5, 6, 9, 3, 2, 9, 0, 9, 6, 3, 2, 9, 5, 2, 2, 7, 4, 4, 3, 0, 4, 3, 5, 5, 7, 6, 6, 8, 9, 6, 6, 4, 8, 9, 5, 0, 4, 4, 5, 2, 4, 4, 5, 2, 3, 1, 6, 1, 7, 3, 1, 8, 5, 6, 4, 0, 3, 0, 9, 8, 7, 1, 1, 1, 2, 1, 7, 2, 2, 3, 8, 3, 1, 1, 3, 6, 2, 2, 2, 9, 8, 9, 3, 4, 2, 3, 3, 8, 0, 3, 0, 8, 1, 3, 5, 3, 3, 6, 2, 7, 6, 6, 1, 4, 2, 8, 2, 8, 0, 6, 4, 4, 4, 4, 8, 6, 6, 4, 5, 2, 3, 8, 7, 4, 9, 3, 0, 3, 5, 8, 9, 0, 7, 2, 9, 6, 2, 9, 0, 4, 9, 1, 5, 6, 0, 4, 4, 0, 7, 7, 2, 3, 9, 0, 7, 1, 3, 8, 1, 0, 5, 1, 5, 8, 5, 9, 3, 0, 7, 9, 6, 0, 8, 6, 6, 7, 0, 1, 7, 2, 4, 2, 7, 1, 2, 1, 8, 8, 3, 9, 9, 8, 7, 9, 7, 9, 0, 8, 7, 9, 2, 2, 7, 4, 9, 2, 1, 9, 0, 1, 6, 9, 9, 7, 2, 0, 8, 8, 8, 0, 9, 3, 7, 7, 6, 6, 5, 7, 2, 7, 3, 3, 3, 0, 0, 1, 0, 5, 3, 3, 6, 7, 8, 8, 1, 2, 2, 0, 2, 3, 5, 4, 2, 1, 8, 0, 9, 7, 5, 1, 2, 5, 4, 5, 4, 0, 5, 9, 4, 7, 5, 2, 2, 4, 3, 5, 2, 5, 8, 4, 9, 0, 7, 7, 1, 1, 6, 7, 0, 5, 5, 6, 0, 1, 3, 6, 0, 4, 8, 3, 9, 5, 8, 6, 4, 4, 6, 7, 0, 6, 3, 2, 4, 4, 1, 5, 7, 2, 2, 1, 5, 5, 3, 9, 7, 5, 3, 6, 9, 7, 8, 1, 7, 9, 7, 7, 8, 4, 6, 1, 7, 4, 0, 6, 4, 9, 5, 5, 1, 4, 9, 2, 9, 0, 8, 6, 2, 5, 6, 9, 3, 2, 1, 9, 7, 8, 4, 6, 8, 6, 2, 2, 4, 8, 2, 8, 3, 9, 7, 2, 2, 4, 1, 3, 7, 5, 6, 5, 7, 0, 5, 6, 0, 5, 7, 4, 9, 0, 2, 6, 1, 4, 0, 7, 9, 7, 2, 9, 6, 8, 6, 5, 2, 4, 1, 4, 5, 3, 5, 1, 0, 0, 4, 7, 4, 8, 2, 1, 6, 6, 3, 7, 0, 4, 8, 4, 4, 0, 3, 1, 9, 9, 8, 9, 0, 0, 0, 8, 8, 9, 5, 2, 4, 3, 4, 5, 0, 6, 5, 8, 5, 4, 1, 2, 2, 7, 5, 8, 8, 6, 6, 6, 8, 8, 1, 1, 6, 4, 2, 7, 1, 7, 1, 4, 7, 9, 9, 2, 4, 4, 4, 2, 9, 2, 8, 2, 3, 0, 8, 6, 3, 4, 6, 5, 6, 7, 4, 8, 1, 3, 9, 1, 9, 1, 2, 3, 1, 6, 2, 8, 2, 4, 5, 8, 6, 1, 7, 8, 6, 6, 4, 5, 8, 3, 5, 9, 1, 2, 4, 5, 6, 6, 5, 2, 9, 4, 7, 6, 5, 4, 5, 6, 8, 2, 8, 4, 8, 9, 1, 2, 8, 8, 3, 1, 4, 2, 6, 0, 7, 6, 9, 0, 0, 4, 2, 2, 4, 2, 1, 9, 0, 2, 2, 6, 7, 1, 0, 5, 5, 6, 2, 6, 3, 2, 1, 1, 1, 1, 1, 0, 9, 3, 7, 0, 5, 4, 4, 2, 1, 7, 5, 0, 6, 9, 4, 1, 6, 5, 8, 9, 6, 0, 4, 0, 8, 0, 7, 1, 9, 8, 4, 0, 3, 8, 5, 0, 9, 6, 2, 4, 5, 5, 4, 4, 4, 3, 6, 2, 9, 8, 1, 2, 3, 0, 9, 8, 7, 8, 7, 9, 9, 2, 7, 2, 4, 4, 2, 8, 4, 9, 0, 9, 1, 8, 8, 8, 4, 5, 8, 0, 1, 5, 6, 1, 6, 6, 0, 9, 7, 9, 1, 9, 1, 3, 3, 8, 7, 5, 4, 9, 9, 2, 0, 0, 5, 2, 4, 0, 6, 3, 6, 8, 9, 9, 1, 2, 5, 6, 0, 7, 1, 7, 6, 0, 6, 0, 5, 8, 8, 6, 1, 1, 6, 4, 6, 7, 1, 0, 9, 4, 0, 5, 0, 7, 7, 5, 4, 1, 0, 0, 2, 2, 5, 6, 9, 8, 3, 1, 5, 5, 2, 0, 0, 0, 5, 5, 9, 3, 5, 7, 2, 9, 7, 2, 5, 7, 1, 6, 3, 6, 2, 6, 9, 5, 6, 1, 8, 8, 2, 6, 7, 0, 4, 2, 8, 2, 5, 2, 4, 8, 3, 6, 0, 0, 8, 2, 3, 2, 5, 7, 5, 3, 0, 4, 2, 0, 7, 5, 2, 9, 6, 3, 4, 5, 0]

>>> def mult(lista):

...     return reduce(mul, lista, 1)

...

>>> mult([])

1

>>> mult([1,2,3])

6

>>> for x in range(1001-5):

...     m = mult(i[x:x+5])

...     if m > maxmult:

...             maxmult = m

...

>>> maxmult

40824


Euler 7 (Python)

Enunciado 7

Listando los primeros seis números primos: 2, 3, 5, 7, 11,y 13, podemos ver que el 6° primo es el 13.

¿Cuál es el 10001° primo?

Solución

La solución fue obtenida en el intérprete interactivo de Python 2.5.2:

>>> from math import sqrt

>>> def primo(n):

...     for i in xrange(2,int(sqrt(n))+1):

...         if n % i == 0:

...             return False

...     return True

>>> a = 2

>>> i = 1

>>> while i < 10002:

...     if primo(a):

...             i +=1

...     a += 1

...

>>> i

10002

>>> a

104744

>>> a-1

104743


Euler 6 (Python)

Enunciado 6

La suma de los cuadrados de los primeros diez números naturales es:

12 + 22 + ... + 102 = 385

El cuadrado de la suma de los primeros diez números naturales es:

(1 + 2 + ... + 10)2 = 552 = 3025

Así que la diferencia entre la suma de los cuadrados de los diez primeros números naturales y el cuadrado de la suma es 3025 − 385 = 2640.

Encontrar la diferencia entre la suma de los cuadrados de los primeros cien números naturales y el cuadrado de la suma.

Solución

La solución fue obtenida utilizando el intérprete interactivo de Python 2.5.2:

>>> def a(n):

...     s = sum(xrange(1,n+1))

...     a1 = s ** 2

...     a2 = sum([x**2 for x in xrange(1,n+1)])

...     return a1, a2, a1-a2

...

>>> a(10)

(3025, 385, 2640)

>>> a(100)

(25502500, 338350, 25164150)

Python tips

  • Con ** podemos elevar un número a cualquier potencia sin necesidad de importar ningún módulo.
  • Para denotar una tupla solo hacen falta las comas (,), no los paréntesis al principio y al final.


Euler 5 (Python)

Enunciado 5

2520 es el menor número que puede ser dividido sin resto por todos los números de 1 a 10. ¿Cuál es el menor número que que puede dividirse sin resto por todos los números de 1 a 20?

Solución

La solución fue obtenida ejecutando el siguiente programa Python 2.5.2:

from math import sqrt

from operator import mul, add



def primo(n):

    for i in xrange(2,int(sqrt(n))+1):

        if n % i == 0:

            return False

    return True



def factorizar(n):

    primos = [x for x in xrange(2,n+1) if primo(x)]

    factores = []

    if n == 1:

        return [1]

    for p in primos:

        if n == p:

                factores.append(p)

                return factores

        if n % p == 0:

                n /= p

                factores.append(p)

                while n % p == 0:

                    n /= p

                    factores.append(p)

    return factores



def mcm(l):

    '''Maximo comun multiplo'''

    ff = [factorizar(i) for i in l]

    singles = list(set(reduce(add,ff)))

    temp = []

    for s in singles:

        temp.extend([s] * max([f.count(s) for f in ff]))

    return reduce(mul,temp,1)



if __name__ == '__main__':

    #print mcm(range(1,11))

    print mcm(range(1,21))

Python tips

  • El módulo operator tiene varias funciones útiles equivalentes a operadores como * y + que pueden utilizarse con funciones como reduce, cuyo primer parámetro es una función.
  • reduce toma una función f de dos argumentos y una lista l. Aplica f a los dos primeros elementos de la lista y obtiene un resultado, luego aplica la función f al resultado con el tercer elemento de la lista, y así sucesivamente hasta consumir toda la lista y retornar el resultado final. Opcionalmente se le puede pasar un tercer parámetro para que la primer llamada a la función f sea aplicada sobre este y el primer elemento de la lista.


Euler 4 (Python)

Enunciado 4

Un número palíndromo se lee igual en ambos sentidos. El mayor palíndromo construido a partir del producto de dos números de dos dígitos es 9009 = 91 × 99.

Encontrar el mayor palíndromo que se puede construir como el producto de dos números de tres dígitos.

Solución

La solución fue obtenida en el intérprete interactivo de Python 3.0rc1+. Necesitaba Python 3 para utilizar itertools.combinations:


juanjo@fenix:~$ python3

Python 3.0rc1+ (py3k, Oct 28 2008, 09:23:29) 

[GCC 4.3.2] on linux2

Type "help", "copyright", "credits" or "license" for more information.

>>> from itertools import combinations

>>> tri = range(999, 99, -1)

>>> mults = []

>>> for a,b in combinations(tri, 2):

...     s = str(a*b)

...     if s == s[::-1]:

...             mults.append(int(s))

... 

>>> max(mults)

906609

Python tips

  • combinations genera la combinación con los elementos de la lista argumento tomados de a n, si se especifica el parámetro n.
  • En Python 3 print deja de ser una sentencia para convertirse en una función, por lo que siempre debe ser llamado con parámetros.
  • unString[::-1] es un idiom usado para invertir una cadena de texto (en el ejemplo, unString). Se lee: los elementos de unString, desde el principio al final, con paso -1.


Euler 3 (Python)

Enunciado 3

Los factores primos de 13195 son 5, 7, 13 y 29.

¿Cual es el mayor factor primo del número 600851475143?

Solución

La solución fue obtenida en el intérprete interactivo de Python 2.5.2:

>>> from math import sqrt

>>> the_number = 600851475143

>>> my_number = sqrt(the_number)

>>> my_number

775146.09922452678

>>> my_number = int(my_number)

>>> my_number

775146

>>> def esprimo(n):

...     for i in xrange(2,int(sqrt(n))+1):

...             if n % i == 0:

...                     return False

...     return True

...

>>> esprimo(8)

False

>>> esprimo(3)

True

>>> esprimo(6823)

True

>>> esprimo(100109)

True

>>> esprimo(100110)

False

>>> for i in xrange(1, my_number+1):

...      if the_number % i == 0 and esprimo(i):

...             print i

...

1

71

839

1471

6857

Python tips

  • xrange, en lugar de crear una lista entera de números como hace range devuelve un generador que va entregando números a medida que los necesitamos.
  • La clase int se instancia para obtener enteros. Si la llamamos con un float como parámetro, podemos usarla para forzar un entero.


Euler 2 (Python)

Enunciado 2

Cada nuevo item en la secuencia de Fibonacci es generado sumando los dos términos previos. Empezando con 1 y 2, los primeros 10 términos serían:

1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...

Encontrar la suma de todos los términos pares en la secuencia que no supera los 4 millones.

Solución

La solución fue obtenida en el intérprete interactivo de Python 2.5.2:

>>> MAX = 4000000

>>> def evsum(n):

...     s = 0

...     a,b = 1,2

...     while True:

...         if a >= n:

...             break

...         if a % 2 ==0:

...             print a, " ",

...             s += a

...         a,b = b,a+b

...     return s

...

>>> evsum(MAX)

2   8   34   144   610   2584   10946   46368   196418   832040   3524578

4613732

Python tips

  • La asignación múltiple es un idom muy cómodo: a,b = 1,2
  • Si agregamos una coma final a la enumeración de objetos a ser impresos con print, se logra el efecto de que no se imprima el salto de línea (\n) final.


Euler 1 (Python)

Project Euler es un sitio web que reta a los programadores a resolver problemas matemáticos mediante código. Me parece entretenido. Voy a ir resolviendo problemas y posteando mi solución en Python acompañada de comentarios sobre el código que puedan servirles a quienes están empezando a aprender el lenguaje.

Enunciado 1

Si listamos todos los números menores a 10 que son múltiplos de 3 o 5, obtenemos 3, 5, 6 y 9. La suma de esos múltiplos es 23.

Encontrar la suma de todos los múltiplos de 3 o 5 menores a 1000.

Solución

La solución fue obtenida en el intérprete interactivo de Python 2.5.2:

>>> def mults(n=10):

...     r = []

...     for i in range(1, n):

...             if i % 3 == 0:

...                     r.append(i)

...             elif i % 5 == 0:

...                     r.append(i)

...     return r

...

>>> mults()

[3, 5, 6, 9]

>>> sum(mults())

23

>>> sum(mults(n=1000))

233168

Python tips

  • En la definición de la función mults se incluye un argumento por defecto n con valor 10. Cuando más adelante se llama a esta función sin parámetros, n toma el valor por defecto.
  • La función range, incluida en el lenguaje devuelve una lista de números sobre la que se puede iterar. Muy útil para usar con la estructura for. Más información haciendo help(range) en el intérprete interactivo.


Intercambio de valores rápido en Python

Cuando empecé a cursar Ingeniería en Sistemas en el año 2003, tuvimos una materia llamada Algoritmos y Estructuras de Datos. La semana del curso estaba compuesta por una clase teórica, una clase práctica y una clase "especial" dictada por un docente de apellido Marina que tenía como objetivo hacernos pensar resolviendo problemas; en las primeras clases ni siquiera programábamos.

El lenguaje de programación de la materia era C y en una de las clases, este docente recordaba risueño que un alumno había querido intercambiar el valor de dos variables

int a = 1;

int b = 2;

haciendo:

a = b;

b = a;

El error es evidente; en a se copia el valor contenido en b (2) pisando el valor original (1) y al ejecutarse la segunda sentencia, el nuevo valor de a (2) es copiado en b.

La siguiente tabla muestra los valores que van tomando las variables a y b: La forma correcta de intercambiar los valores habría sido utilizando una variable auxiliar en la cual mantener uno de los valores:

int aux;

int a = 1;

int b = 2;

aux = a;

a = b;

b = aux;

La siguiente tabla muestra los valores que van tomando las variables aux, a y b:

Lo gracioso del asunto es que unos años más tarde conocí otro lenguaje de programación, Python.

En Python un tipo de dato que viene con el lenguaje es la tupla. Una tupla es una secuencia (sus elementos tienen orden) inmutable (no se puede cambiar su tamaño o contenido) que puede tener dentro objetos de distinto tipo. Un ejemplo de tupla en Python (contiene tres números y dos cadenas de texto):

(1, 2, "tres", 4, "Juan")

La forma de apuntar a ese objeto desde una variable es simplemente:

a = (1, 2, "tres", 4, "Juan")

Aunque podemos obviar los paréntesis y de todas formas funcionará. Decimos que la tupla es empaquetada:

a = 1, 2, "tres", 4, "Juan"

De forma similar, podemos desempaquetar la tupla en nuevas variables:

b, c, d, e, f = a

La condición es que el número de variables en el lado izquierdo del operador = coincida con el número de elementos en la tupla.

La siguiente sentencia, empaqueta y desempaqueta:

x, y, z = "Juan", 100, 1

Y es equivalente a:

x = "Juan"

y = 100

z = 1

Finalmente, esta propiedad del lenguaje nos permite intercambiar rápidamente los valores de 2 (o n) variables:

a = 1

b = 2

a, b = b, a

Así, lo que un alumno despistado quiso hacer en 2 sentencias y Marina mostró que se hacía correctamente en 3, yo lo hago en 1 :)