Anuncios

Bienvenidos sean a este post, hoy continuaremos con lo visto en el post anterior sobre dos tipos de comprensiones adicionales.

Anuncios

Comprension anidada

Una comprension anidada es usualmente utilizada para cuando tenemos bucles anidados, esto se debe porque al manejar algoritmos para iterar en una secuencia se utilizan dos contenedores donde el primero corre por toda la secuencia de izquierda a derecha, el segundo hace lo mismo pero en lugar de comenzar de la posicion 0 lo hace de la 1, la idea es probar todos los pares sin duplicacion, veamos el primer ejemplo:

>>> elementos = 'ABCD'
>>> pares = []
>>> for a in range(len(elementos)) :
...     for b in range(a, len(elementos)) :
...             pares.append((elementos[a], elementos[b]))
... 
>>>
Anuncios
Anuncios

Primero tenemos los elementos que usaremos para nuestros dos bucles, en realidad son una serie de letras que combinaremos por pares, lo siguiente es una lista que llamaremos pares, luego tendremos un bucle for que guardara las posiciones en base al tamaño de elementos, despues usaremos otro for donde almacenara tambien todas las posiciones pero en este caso le estableceremos el rango en base al valor de a y la longitud de elementos, despues por medio de append agregaremos en pares primero la posicion almacenada en a de elementos y luego la posicion en b de elementos, creando el par de combinaciones, una vez terminado el ciclo recien el otro bucle cambiara de posicion y volveremos a repetir todo el segundo bucle y asi sucesivamente, si lo probamos veremos esto:

>>> pares
[('A', 'A'), ('A', 'B'), ('A', 'C'), ('A', 'D'), ('B', 'B'), ('B', 'C'), ('B', 'D'), ('C', 'C'), ('C', 'D'), ('D', 'D')]
>>>
Anuncios

Observen como nos guardo todas las combinaciones de pares a partir de la posicion que informamos en el segundo bucle, vamos a transformar este codigo en una lista con comprension:

>>> elementos = 'ABCD'
>>> pares = [(elementos[a], elementos[b])
...     for a in range(len(elementos))
...     for b in range(a, len(elementos))
... ]
>>>
Anuncios

En este caso volvemos a tener elementos, luego tomamos a pares directamente primero estableceremos los datos que almacenaremos por medio de los elementos en las posiciones a y b, nuestro siguiente paso primero crear un bucle for para establecer el valor de a, luego estableceremos el valor b pero como en el caso anterior hasta que no termine el bucle de b no pasara al bucle de a, con esto creamos una comprension mejor con la anterior, veamos si funciono de la misma forma:

>>> pares
[('A', 'A'), ('A', 'B'), ('A', 'C'), ('A', 'D'), ('B', 'B'), ('B', 'C'), ('B', 'D'), ('C', 'C'), ('C', 'D'), ('D', 'D')]
>>>
Anuncios

Como podemos ver pudimos resolver de una manera mas simple el primer codigo, si se preguntan porque lo hice de esta forma la comprension, fue por un tema de visibilidad porque se podria haber hecho de corrido pero esteticamente iba a quedar ilegible pero recuerden siempre que el codigo este entre parentesis, llaves o corchetes (como este caso) el lenguaje sabra como interpretarlo, pasemos al siguiente tema.

Anuncios

Filtrando comprensiones

Como su titulo lo indica en las comprensiones podemos filtrar informacion, para entender este concepto vamos a crear un ejemplo que encuentre todos los triples pitagoricos cuyos lados mas cortos sean menores a 10, veamos el codigo:

>>> from math import sqrt
>>> max = 10
>>> triples = [(a, b, sqrt(a ** 2 + b ** 2))
...     for a in range(1, max) for b in range(a, max)]
>>> triples = list(filter(
...     lambda triple: triple[2].is_integer(), triples))
>>>
Anuncios
Anuncios

Primero importaremos a sqrt para poder calcular raiz cuadrada, luego estableceremos el valor maximo de los lados cortos, despues definiremos a triples donde primero iran los valores generados por el primer bucle, luego los del segundo bucle y por ultimo la raiz cuadrada del valor de a al cuadrado mas el valor de b al cuadrado, es decir pitagoras, despues tenemos los dos bucles que determinan el valor de a y b respectivamente por medio de range que iran desde 1 hasta el valor de max pero si nosotros lo probamos veremos que nos devolvera en el valor de la hipotenusa numeros flotantes y nosotros queremos de tipo entero, para eso utilizamos a filter pero dentro de un list, en este caso usamos una funcion anonima donde verificaremos si la tercer posicion de este tuple es de tipo entero, es decir si es de tipo entero lo deja pasar de lo contrario lo omite, si lo probamos veremos la siguiente salida:

>>> print(triples)
[(3, 4, 5.0), (6, 8, 10.0)]
>>>
Anuncios

Observen como solamente nos trajo dos valores donde la hipotenusa es un valor de tipo entero pero como pueden ver es de tipo float y nosotros queremos que se de tipo int, para ello vamos a modificar el codigo anterior de la siguiente manera:

>>> from math import sqrt
>>> max = 10
>>> triples = [(a, b, sqrt(a ** 2 + b ** 2))
...     for a in range(1, max) for b in range(a, max)]
>>> triples = filter(lambda triple : triple[2].is_integer(), triples)
>>> triples = list(map(
...     lambda triple: triple[:2] + (int(triple[2]), ), triples))
>>>
Anuncios

Si observan hasta que aplicamos el filtro funciona de la misma forma pero despues de este agregamos otro list y despues un map, dentro de este map usaremos una funcion anonima pero esta vez usaremos solo la tercer posicion de la lista triples y en este caso le cambiaremos el valor por medio de int al valor en esa posicion, el resto no debera modificarlo, veamos como es su salida:

>>> print(triples)
[(3, 4, 5), (6, 8, 10)]
>>>
Anuncios

Como pueden ver logramos el objetivo pero complejo de manera innecesario, no? Entonces tomemos el ejemplo y apliquemos una comprension de list mediante el siguiente codigo:

>>> from math import sqrt
>>> max = 10
>>> triples = [(a, b, sqrt(a ** 2 + b ** 2))
...     for a in range(1, max) for b in range(a, max)]
>>> triples = [(a, b, int(c)) for a, b, c in triples if c.is_integer()]
>>>
Anuncios

Las tres primeras lineas son exactamente iguales a los casos anteriores pero ahora pasaremos los tres valores que necesitamos observen como usamos el int para el valor de c, despues usamos un bucle que toma los tres valores de triples y por ultimo tenemos un condicional donde solo permitira pasar los valores donde c sea de tipo entero, si lo probamos veremos esto:

>>> print(triples)
[(3, 4, 5), (6, 8, 10)]
>>>
Anuncios

Podemos ver como logramos el mismo objetivo pero de una forma mas limpia, reducida y mas python, faltan dos formas mas pero las veremos en el proximo post.

Anuncios

En resumen, hoy hemos visto como trabajar con comprensiones pero de dos formas distintas, la primera por medio de bucles anidados, como es su logica, como la podemos equiparar y como nos beneficia, despues vimos una forma para crear filtracion a traves de comprensiones, como podemos elegir el camino dificil o el camino por medio de la comprension con list, espero les haya sido util sigueme en tumblr, Twitter o Facebook para recibir una notificacion cada vez que subo un nuevo post en este blog, nos vemos en el proximo post.

Anuncios

Donación

Es para mantenimento del sitio, gracias!

$1.00