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

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


La historia de Python: Cómo todo se convirtió en sentencias ejecutables

El siguiente texto es una traducción del artículo How Everything Became an Executable Statement de Guido van Rossum publicado en http://python-history.blogspot.com/.

Cómo todo se convirtió en sentencias ejecutables

Los nuevos usuarios de Python a veces se sorprenden al descubrir que todas las partes del lenguaje son sentencias ejecutables, incluyendo la definición de funciones y clases. Eso significa que cualquier sentencia puede aparecer en cualquier lugar en un programa. Por ejemplo, una definición de una función puede aparecer dentro de una sentencia "if" si así se lo desea.

En una versión muy temprana de la gramática de Python esto no era así: los elementos de la gramática tenían un "sabor decorativo", las sentencias import y la definición de funciones solo eran permitidas en el nivel superior de un módulo o script (dónde eran ejecutadas para efectivizarse).

De todas formas, cuando estaba agregando soporte para clases, decidí que esto era muy restrictivo.

Mi razonamiento fue más o menos como sigue. En lugar de definir el cuerpo de una clase sólo como una serie de declaraciones de funciones, también parecía adecuado permitir asignaciones a variables allí. De todas formas, si iba a permitir eso, ¿por qué no ir un escalón más arriba y permitir código ejecutable arbitrario? O, llevando esto aún más lejos, ¿por qué no permitir declaración de funciones dentro de sentencias "if", por ejemplo? Rápidamente se vio que esto permitía una simplificación de la gramática, ya que ahora todos los usos de sentencias (estén identados o no) podían compartir la misma regla de gramática, y de hecho el compilador podría usar la misma función generadora de byte code para todas ellas.

A pesar de que este razonamiento me permitía simplificar la gramática y los usuarios podían colocar sentencias Python en cualquier lugar, esta característica no habilitaba necesariamente ciertos estilos de programación. Por ejemplo, la gramática de Python técnicamente permitía a los usuarios escribir cosas como funciones anidadas aunque la semántica subyacente de Python no aceptara ámbitos anidados. Por lo tanto, el código así operaría de formas inesperadas o "rotas" comparadas con lenguajes que realmente estaban diseñados con esa característica en mente. Con el paso del tiempo, muchas de esas características "rotas" se arreglaron. Por ejemplo, la definición de funciones anidadas sólo empezó a funcionar un poco más correcta en Python 2.1.

Traducido por Juan José Conti.

Revisado por César Portela.

Si encontrás errores en esta traducción, por favor reportalos en un comentario y los corregiremos a la brevedad.

Todas las traducciones de esta serie pueden encontrarse en La historia de Python.


La historia de Python: Todo de primera clase

El siguiente texto es una traducción del artículo First-class Everything de Guido van Rossum publicado en http://python-history.blogspot.com/.

Todo de primera clase

Uno de mis objetivos para Python era hacerlo de tal forma que todos los objetos sean de "primera clase". Con esto me refiero a que quería que todos los objetos puedan ser nombrados en el lenguaje (por ejemplo, enteros, strings, funciones, clases, módulos, métodos, etc.) para tener igual status. Entonces pueden ser asignados a variables, ubicados en listas, almacenados en diccionarios, pasados como argumentos y más.

La implementación interna de Python hizo que esto sea fácil de hacer. Todos los objetos de Python estaban basados en una estructura de datos de C común que se usaba en todos los lugares del intérprete. Variables, listas, funciones y todo lo demás usaba variaciones de esta estructura de datos; directamente no importaba si la estructura representaba un objeto simple como un entero o algo más complicado como una clase.

Aunque la idea de tener "todo de primera clase" es conceptualmente simple, había aún un aspecto de las clases que necesitaba resolver; el problema de hacer que los métodos sean objetos de primera clase.

Consideremos esta clase simple en Python (copiada de la entrada de la semana pasada):

class A:

    def __init__(self,x):

        self.x = x

    def spam(self,y):

        print self.x, y

Si los métodos van a ser objetos de primera clase, entonces pueden ser asignados a otras variables y usados como cualquier otro objeto en Python. Por ejemplo, alguien podría escribir una sentencia en Python como "s = A.spam". En este caso la variable "s" referencia un método de una clase, que en realidad es solo una función. Sin embargo, un método no es exactamente igual a una función. En concreto, se supone que el primer argumento de un método es una instancia de la clase en la que el método fue definido.

Para tratar esto cree un tipo de objeto invocable (callable) conocido como "unbound method". Un unbound method era en realidad un wrapper delgado alrededor de un objeto función que implementaba un método, pero forzaba la restricción de que el primer argumento tenía que ser una instancia de la clase en la cual el método fue definido. Así, si alguien quería llamar al unbound method "s" como una función, tendrían que pasar una instancia de la clase "A" como primer argumento. Por ejemplo, "a = A(); s(a)".(*)

Un problema relacionado ocurre si alguien escribe una sentencia Python que refiere al método en una instancia específica de un objeto. Por ejemplo, alguien puede crear una instancia usando "a = A()" y luego escribir una sentencia como "s = a.spam". Aquí la variable "s" nuevamente referencia al método de una clase, pero la referencia a ese método se obtuvo a través de la instancia "a". Para manejar esta situación se usa un objeto invocable diferente llamado "bound method". Este objeto es también un wrapper delgado alrededor del objeto función para el método. Sin embargo, este envoltorio implícitamente almacena la instancia original que fue usada para obtener el método. Así, una sentencia futura como "s()" llamará al método implícitamente con la instancia "a" como el primer argumento.

En realidad el mismo objeto interno es usado para representar los bound y unbound methods. Uno de los atributos de este objeto contiene una referencia a una instancia. Si es None, el método es unbound. De otro modo, el método es bound.

A pesar de que bound y unbound methods parezcan un detalle sin importancia, son una parte crítica de como las clases funcionan bajo el tapete. Siempre que una sentencia como "a.spam()" aparece en un programa, la ejecución de la sentencia ocurre en dos partes. Primero ocurre la búsqueda de "a.spam". Esto retorna un bound method; un objeto invocable. Luego, una operación de llamado de función "()" es aplicada a ese objeto para invocar el método con los argumentos provistos por el usuario.

(*) En Python 3000, el concepto de unbound methods se eliminó y la expresión "A.spam" retorna un objeto función normal. Nos dimos cuenta de que la restricción de que el primer argumento sea una instancia de A ayudaba pocas veces al diagnosticar problemas y frecuentemente era un obstáculo para usos avanzados; alguien lo llamó "duck typing self", el cual parece un nombre apropiado.

Traducido por Juan José Conti.

Revisado por César Portela.

Si encontrás errores en esta traducción, por favor reportalos en un comentario y los corregiremos a la brevedad.

Todas las traducciones de esta serie pueden encontrarse en La historia de Python.