Mostrando entradas con la etiqueta Retos. Mostrar todas las entradas
Mostrando entradas con la etiqueta Retos. Mostrar todas las entradas

domingo, 20 de marzo de 2022

Diccionario con Tupla

 

Reto: Diccionario con Tupla

Crear un diccionario donde la clave sean los números del 1 al 100, y para cada uno de los números tenemos una tupla como valor, donde la tupla contiene el cuadrado de ese número, e indica si el número es primo o no.

Método 1

Usando una fucción que ya enseñamos en el blog que retorna si el numero es primo o no, y recorriendo los 100 numeros
 from math import sqrt  
   
   
 # Funcion que determina si es un numero primo  
 def sera_primo(n):  
   primo = True # inicialmente un número es primo hasta que no se demuestre lo contrario  
   for j in range(3, int(sqrt(n)+1), 2):  
     if (n % j == 0): # si el módulo es cero se debe a que es divisible y por tanto no es primo  
       primo = False  
       break  
   return primo  
   
 miDiccionario = {}  
 for i in range(1, 101):  
   # Añadimos a la lista el cuadrado y comprobamos si es primo  
   miDiccionario[i] = (i ** 2,sera_primo(i^2))  
   
 print(miDiccionario)  

viernes, 11 de marzo de 2022

Reto: Tuplas

Crear una tupla con las cuatro estaciones del año. Imprimir la tupla, imprimir su longitud e imprimir los elemento de la tupla uno a uno.


Utilizamos una tupla en lugar de una lista para contener las estaciones del año.

Las tuplas a diferencia de los arrays se declaran usando parentesis (), en lugar de corchetes [].

 

Método 1

Definimos nuestra variable tipo tupla. Imprimimos su valor y su longitud. Finalmente la recorremos con un for para imprimir cada una en una linea diferente.

 tupla = ("Invierno", "Primavera", "Verano", "Otoño")
 print(*tupla)
 print(f"Longitud: {len(tupla)}")
 for estacion in tupla:
     print(estacion)  

lunes, 8 de julio de 2019

Índice de masa corporal

Reto: Índice de masa corporal

Crear una función que calcule el Índice de Masa Corporal (Body Mass Index [BMI]).


La fórmula para calcular el IMC es:







Y la manera de clasificarlo que vamos ha usar nosotros es esta:

ÍNDICE MASA CORPORAL  CLASIFICACIÓN
<16.00 Infrapeso: Delgadez Severa
16.00 - 16.99 Infrapeso: Delgadez Moderada
17.00 - 18.49 Infrapeso: Delgadez Aceptable
18.50 - 24.99 Peso Normal
25.00 - 29.99 Sobrepeso
30.00 - 34.99 Obeso: Tipo I
35.00 - 40.00 Obeso: Tipo II
>40.00 Obeso: Tipo III

Método 1

Creamos una función para calcular los valores que nos den. Vamos poniendo esos valores a la vez que se los vamos diciendo al usuario para que pueda ver que hemos entendido. Después llamamos a la función para que nos calcule el IMC y le imprimimos el valor.

 def BMI(a,p):  
   IMD=p/a**2  
   return(IMD)  
 altura = float(input('Dime tu altura por favor') or 1.7)  
 print('Altura=',altura,'m')  
 peso = float(input('Dime tu peso por favor')or 60)   
 print('Peso=',peso,'Kg')  
 print('Tu Indice de Masa Corporal es',round(BMI(altura,peso),2))  

Método 2

Este es el mismo método que el anterior pero también se le dice al usuario en que clasificación cae.

 def BMI(a,p):  
   IMD=p/a**2  
   return(IMD)  
 altura = float(input('Dime tu altura por favor') or 1.7)  
 print('Altura=',altura,'m')  
 peso = float(input('Dime tu peso por favor')or 60)   
 print('Peso=',peso,'Kg')  
 ibc=round(BMI(altura,peso),2)  
 print('Tu Indice de Masa Corporal es',ibc)  
 if ibc<=16:  
  print("Tienes Delgadez Severa")  
 elif ibc>16 and ibc<17:  
  print("Tienes Delgadez Moderada")  
 elif ibc>=17 and ibc<18.50:  
  print("Tienes Delgadez Aceptable")  
 elif ibc>=18.50 and ibc<25:  
  print("Tienes Peso Normal")  
 elif ibc>=25 and ibc<30:  
  print("Tienes Sobrepeso")  
 elif ibc>=30 and ibc<35:  
  print("Obeso: Tipo I")  
 elif ibc>=35 and ibc<40:  
  print("Obeso: Tipo II")  
 elif ibc>=40:  
  print("Obeso: Tipo III")  

miércoles, 29 de agosto de 2018

Generar y ordenar palabras en Python

Reto: Ordenar palabras

Crear una serie de 10 palabras donde sus letras se obtienen de forma aleatoria. Mostrar estas palabras y mostrar esas mismas palabras ordenadas alfabéticamente.



Método 1

Creamos la lista frase que contendrá diez palabras compuestas cada una de ellas por cuatro letras aleatorias. La variable L contienen todo el abecedario en forma de lista. El primer bucle for contiene diez ciclos para generar las diez palabras. En el segundo bucle for es donde generamos cada palabra recogida como string en la variable p. Para ello, se elige aleatoriamente cada letra de la lista L.
Una vez generada la palabra p está se añade a la lista L con append.


import random
frase=[]
L=list('abcdefghijklmnopqrstuvwxyz')
for i in range(0,11):
  p=''
  for j in range(4):
    p+=L[random.randint(0,25)]
  frase.append(''.join(p))
print(frase)
print(sorted(frase))


Método 2

Con este método vamos a crear palabras donde se alternen parejas de consonante y vocal. La variable n contiene el número de parejas elegidas. Si n es tres obtendremos palabras con seis letras. La variable c es un string que contiene las consonantes y la variable v es otra cadena con las vocales. Inicializamos la variable L como lista vacía. Nos metemos en un primer bucle for de diez ciclos para generar las diez palabras. El segundo bucle for añade aleatoriamente una letra consonante y luego una letra vocal para que formen parejas, y se repite n veces.

import random
n=3 # nº de parejas de letras consonante-vocal
c='bcdfghjklmnpqrstvwxyz'
v='aeiou'
L=[]
for i in range(10):
  palabra=''
  for j in range(n):
    palabra+=''.join(random.choice(c))
    palabra+=''.join(random.choice(v))
  L.append(palabra)
print(L)
print(sorted(L))

domingo, 19 de agosto de 2018

Aleatorios con excepciones

Reto: Aleatorios con excepciones

Generar números aleatorios pares entre 100 y 130, salvo 110 y 120.

Veamos varios casos, que pueden ser:

  • con repetición
  • sin repetición




Método 1

Importamos la librería random. Creamos la lista L inicialmente vacía. Nos metemos en un bucle for con 16 ciclos. Por cada vuelta generamos un número aleatorio par entre 100 y 130. Si el número generado no es 110, ni 120, entonces se añade a la lista con append.
Finalmente se imprime la lista y luego se vuelve a imprimir ordenada con sorted.

import random
L = []
for i in range(16):
    x = random.randrange(100,131,2)
    if x not in (110,120):
        L.append(x)
print(L)
print(sorted(L))


Método 2

Este método realiza un tratamiento similar al anterior pero usa List Comprehensions para comprimir el código en una sola línea.

import random
L=[r for r in [random.randint(100,130) for s in range(30)] if r%2==0 and r not in (110,120)]
print(L)
print(sorted(L))


Método 3

En este caso no importamos la librería random completa, únicamente importamos el método randint que genera números aleatorios entre 50 y 65. Con un if eliminamos aquellos valores que sean 55 o 60. El valor de la variable i que supere el filtro se multiplica por 2 para obtener los pares entre 100 y 130, excluidos del tratamiento los valores 110 y 120.

from random import randint
L = [i*2 for i in [randint(50,65) for j in range(16)] if i not in (55,60)]
print(L)
print(sorted(L))


Método 4

Este método es similar al método anterior si bien no es necesario multiplicar i por dos ya que los valores generados exigimos que sean pares incluyéndolo como una condición adicional en el if.

import random
L = [i for i in [random.randint(100,130) for j in range(30)] if i not in (110,120) and i%2==0]
print(L)
print(sorted(L, reverse=True))


Método 5

Usamos random.sample que nos permite elegir una muestra aleatoria entre los valores generados. En este caso los valores obtenidos serán sin repetición gracias a que este método está diseñado para elegir sin repetición de una secuencia de números.

import random
L=[i for i in random.sample(range(100,131,2),16) if i not in (110,120)]
print(L)
L.sort(reverse=True)
print(L)


Método 6

Usamos random.shuffle sobre la lista generada previamente. Este método devuelve una nueva lista mezclada, lo que permite obtener un resultado sin repetición.

import random
L=[i for i in range(100,131,2) if i!=110 and i!=120]
random.shuffle(L) #desordena la lista
print(L)
print(sorted(L))

sábado, 4 de agosto de 2018

Generar números aleatorios sin repetición y ordenarlos en Python

Reto: Ordenar números

Imprimir una lista de 10 números aleatorios sin repetición que varíen en el rango 80 a 99. Volver a imprimir la lista pero ordenada.




Método 1

Definimos la función unico que tiene dos argumentos. La función, dado el número x y la lista L, detecta si x es único o esta repetido. Si el número x no está en la lista entonces retorna True, y si el número se encuentra ya en la lista entonces devuelve False.
El bucle while nos proporciona los 10 números aleatorios sin repetición que ha de llegar a tener la lista. En este caso el bucle ha de ser del tipo while, no valdría un for, ya que no conocemos el número de ciclos que serán necesarios, puesto que si no existen repeticiones serán 10 ciclos pero si las hay el número aumenta. Por cada repetición encontrada se ha de generar un nuevo x aleatorio. Los x únicos generados se anexionan a la lista con append.
Finalmente se imprime la lista L y se ordena con sort.




import random
def unico(x,L):
  esUnico=True
  for i in range(len(L)):
    if x==L[i]:
      esUnico=False
      break
  return esUnico
L=[]
j=0
while j<10:
  x=random.randint(80,99)
  if unico(x,L):
    L.append(x)
    j+=1
print(L)
L.sort()
print(L)


Método 2

Inicializamos la lista L con su primer valor, el de la posición cero. Esto se hace fuera del bucle while ya que el primer x estamos seguros de que no se repite respecto a los anteriores, ya que es el primero. Luego nos metemos en un bucle while que genera los demás x aleatorios que de momento son candidatos, hasta que no se compruebe que no están repetidos entre los elementos que ya se encuentran en la lista. Para conseguir establecer si el número candidato se ha de anexionar a la lista o no se hace usando un bucle for que contiene un condicional if. La clave está en el else que no pertenece al if sino al for.
Finalmente imprimimos la lista L y la ordenamos con sorted.

import random
L=[random.randint(80, 99)] #este es L[0]
i=1
while i<10:
  x=random.randint(80,99)
  for j in range(0, len(L)):
    if L[j]==x:
      break
  else:
    L.append(x)
    i+=1
print(L)
print(sorted(L))


Método 3

Esta es una variante del método anterior que mejora el código ya que usa en el if la instrucción in, o mejor dicho, not in, para detectar si el nuevo número aleatorio se encuentra entre los que ya se han añadido a la lista L.


import random
L=[random.randint(80, 99)] #este es L[0]
i=1
while i<10:
  x=random.randint(80,99)
  if x not in L:
    L.append(x)
    i+=1
print(L)
print(sorted(L))


Método 4

Importamos únicamente el método sample de la librería random que permite crear una lista eligiendo aleatoriamente 10 valores de un rango de números creado con range que varía entre 80 y 100 (excluido el 100).

Con sorted ordenamos la lista . Si deseamos que la ordenación sea inversa tendremos que indicarlo poniendo print(sorted(L,reverse=True)).

from random import sample
L=sample(range(80,100),10)
print(L)
print(sorted(L))


Método 5

Este método, al igual que el anterior, utiliza sample para elegir una muestra aleatoria entre los posibles valores que generamos utilizando List Comprehension.
Faltaría ordenar la lista, pero hemos preferido dejar el código así para que se vea que en dos líneas se puede llegar a obtener la lista de aleatorios sin repetición.


from random import sample
print(sample([x for x in range(80,100)],10))


Método 6

Creamos la lista L usando list y range. Esta lista contendrá todos los números enteros consecutivos entre 80 y 99. La instrucción random.shuffle(L) baraja aleatoriamente la lista L. Creamos la lista L10 que contendrá los 10 primeros elementos de la lista L. Imprimimos la lista L10. Ordenamos la lista L10 en sentido inverso usando sort. Si la queremos ordenar en sentido creciente simplemente dejaremos vacío lo que va entre sus paréntesis. Sería L10.sort().


import random
L=list(range(80,100))
random.shuffle(L) #baraja la lista
L10=L[:10] #crea otra lista con los 10 primeros elementos
print(L10)
L10.sort(reverse=True) #ordena la lista L10
print(L10)

viernes, 3 de agosto de 2018

Años bisiestos en Python

Reto: Bisiesto

Crear una función que dado un año diga si es bisiesto.



Podemos consultar la Wikipedia para saber qué años son bisiestos.
El calendario Juliano dio paso a calendario Gregoriano en 1582. Desde entonces se estableció la regla que nos dice cuando una año es bisiesto y por lo tanto tiene 366 días, en lugar de 365, ya que se añade un día más el 29 de febrero.

  • Un año es bisiesto si es múltiplo de 4, salvo que...
    • el año termine en 00, en cuyo caso, no será bisiesto, salvo que ...
      • el año sea múltiplo de 400, en cuyo caso, si será bisiesto.
Como podemos observar para que un año sea bisiesto existe una regla general (que sea múltiplo de 4) pero a esta regla general existe una excepción (que el año termine en 00, esto es, los finales de siglo) en cuyo caso el año no será bisiesto, y finalmente existe una excepción a la excepción anterior (que el año sea múltiplo de 400) en cuyo caso el año si será bisiesto.

Así por ejemplo, los años 2100, 2200, 2300 no serán bisiestos, pero el 2400 si lo será.


Método 1

Definimos una función que contiene un if con una condición lógica compleja que resume la regla que nos da el año bisiesto.




def bisiesto(x):
  if x%4==0 and (not(x%100==0) or x%400==0 ):
    texto='es bisiesto.'
  else:
    texto='es un año NO bisiesto.'
  return texto
x=int(input('Introduzca un año entre 1600 y 2500:'))
print(x,bisiesto(x))


Método 2

Generamos un año aleatorio y definimos una función que nos retornará True si se trata de una año bisiesto y nos retornará False si el año generado no es bisiesto. Con este método hemos optado por realizar varios if concatenados para resolver la lógica de los años bisiestos.

import random
random.seed()
x=random.randint(1600,2500)
def bisiesto(x):
  if x%4==0:
    if x%100==0:
      if x%400==0:
        return True
      else:
        return False
    else:
      return True
  else:
    return False
if bisiesto(x):
  print(x,'es un año bisiesto.')
elif not(bisiesto(x)):
  print(x,'no es un año bisiesto')


Método 3

Aplicamos en cascada los condicionales para llegar a la definición de año bisiesto que da la Wikipedia.

def is_leap(year):
    if year%400==0:
        return True
    else:
        if year%100==0:
            return False
        else:
            if year%4==0:
                return True
            else:
                return False
print('El año {} ¿es bisiesto?: {}'.format(1800,is_leap(1800)))
print('El año {} ¿es bisiesto:? {}'.format(1900,is_leap(1900)))
print('El año {} ¿es bisiesto:? {}'.format(2000,is_leap(2000)))
print('El año {} ¿es bisiesto:? {}'.format(2040,is_leap(2040)))
print('El año {} ¿es bisiesto:? {}'.format(2400,is_leap(2400)))
print('El año {} ¿es bisiesto:? {}'.format(2100,is_leap(2100)))
print('El año {} ¿es bisiesto:? {}'.format(2200,is_leap(2200)))
print('El año {} ¿es bisiesto:? {}'.format(2300,is_leap(2300)))
print('El año {} ¿es bisiesto:? {}'.format(2500,is_leap(2500)))


Método 4

Este método es equivalente al anterior pero necesita menos líneas. Se van probando tres condicionales if por ese orden. Si el primero es cierto se entra dentro y se ejecuta el return que contiene, y ya no se sigue. Si es falso se pasa a evaluar el siguiente if, y así con el resto de los condicionales. Si no se cumple ninguno de los tres se ejecuta el último return que indica que el año analizado no es bisiesto. Esto se basa en la idea de que en una función cuando se ejecuta un return ya no se sigue con el código restante de la función.

def is_leap(year):  
  if year%400==0: return True  
  if year%100==0: return False  
  if year%4==0: return True  
  return False  
print('El año {} ¿es bisiesto?: {}'.format(1800,is_leap(1800)))
print('El año {} ¿es bisiesto:? {}'.format(1900,is_leap(1900)))
print('El año {} ¿es bisiesto:? {}'.format(2000,is_leap(2000)))
print('El año {} ¿es bisiesto:? {}'.format(2040,is_leap(2040)))
print('El año {} ¿es bisiesto:? {}'.format(2400,is_leap(2400)))
print('El año {} ¿es bisiesto:? {}'.format(2100,is_leap(2100)))
print('El año {} ¿es bisiesto:? {}'.format(2200,is_leap(2200)))
print('El año {} ¿es bisiesto:? {}'.format(2300,is_leap(2300)))
print('El año {} ¿es bisiesto:? {}'.format(2500,is_leap(2500)))

Series en Python

Reto: Series

Listar los números entre un valor inicial y uno final, con un cierto intervalo. Al final dar la suma de todos los valores listados.




Método 1

Establecemos tres valores concretos para las variables inicial, final e intervalo. Con el objeto de llegar a calcular la suma total creamos la variable total que inicializamos a cero. Nos metemos en un bucle for para recorrer con range todos los valores del rango usando el intervalo establecido. El objeto range nos permite recorrer un rango comenzando por el inicio, pero no llegando nunca al final exactamente. Observe que en la imagen no aparece listado el final que es 20.

La variable total actúa como acumulador sumando en cada vuelta del bucle el valor que tome la variable i en ese momento. Finalmente, y fuera del bucle imprimimos el valor de la variable total.



inicial=10
final=20
intervalo=2
total=0 #inicializamos la suma a cero
for i in range(inicial,final,intervalo):
  total+=i #la variable total actúa de acumulador
  print(i)
print('La suma es:',total)


Método 2

Generamos valores aleatorios para las variable inicial, final e intervalo. Imprimimos por pantalla los valores obtenidos. Creamos la variable i que luego usaremos en el bucle while y la inicializamos con el valor inicial. Creamos la lista L y la inicializamos como una lista vacía. La variable total inicialmente valdrá cero. Nos metemos en un bucle while que durará mientras la variable i sea menor que el valor final. Con append vamos añadiendo a la lista L los valores del intervalo dados por la variable i. Dentro del bucle while incrementamos el valor de la variable i con el importe del intervalo. Acumulamos los valores obtenidos en la variable total. Fuera del bucle imprimimos la lista L y mostramos el importe de la suma.



import random
random.seed() #barajamos la serie de números aleatorios
inicial=random.randint(100,130)
final=inicial+random.randint(10,20)
intervalo=random.randint(2,5)
print('inicial=',inicial)
print('final=',final)
print('intervalo=',intervalo)
i=inicial
L=[] #inicializamos L como una lista vacía
total=0 #inicializamos la suma a cero
while i<final:
  L.append(i) #añadimos el valor i a la lista L
  i+=intervalo #aumentamos el valor del contador
  total+=i
print(L) #imprimimos la lista
print('La suma es:',total)

Método 3

Un método muy sencillo y efectivo.
total=0
for x in range(1, 26):
  if x%5==0:
    total+=x  #acumulador
    print(x)
print("El total es: ",total)

Operaciones con números en Python

Reto: Operaciones con números

Dados dos números hacer con ellos las operaciones básicas.




Consulte la entrada titulada:



Método 1

Inicialmente hacemos que la variable x valga 15 y la variable y tome un valor de 3. Calculamos e imprimimos la suma, resta, multiplicación y división. Luego damos nuevos valores a x e y, en una sola línea de código. Calculamos la potencia x elevado a y. Damos a x el valor 11 y calculamos la división entera y el módulo.

x=15
y=3
print(x,'+',y,'=',x+y)
print(x,'-',y,'=',x-y)
print(x,'*',y,'=',x*y)
print(x,'/',y,'=',x/y)
x,y=2,3
print(x,'elevado a',y,'=',x**y)
x=11
print(x,'división entera entre',y,'=',x//y)
print(x,'módulo',y,'=',x%y)
#operadores lógicos
print(x,'es mayor que',y,x>y)
print(x,'es menor que',y,x<y)
print(y,'<',x,'<20',y<x<20)


Método 2

Generamos aleatoriamente los valores x e y. Calculamos al suma, resta, multiplicación y potencia. Para la división creamos una función con un control de excepciones para evitar la división por cero. Con try hacemos la división normal pero si detectamos que se puede llegar a producir un erro de ZeroDivisionError lo que hacemos con except es evitar ese error y en su lugar la función retorna un texto que informa del motivo de no haber realizado la división. Con ello evitamos que el programa lance un error que detenga la ejecución y confunda al usuario. También creamos una función para la división entera y otra para el cálculo del módulo con el control de excepciones correspondiente.


import random
x=random.randrange(1,10,2) #genera impares entre 1 y 9
y=random.randrange(3) #genera 0,1,2
print(x,'+',y,'=',x+y)
print(x,'-',y,'=',x-y)
print(x,'*',y,'=',x*y)
print(x,'elevado a',y,'=',x**y)
def div(x,y):
    try: return x/y
    except ZeroDivisionError: return 'error: denominador cero'
print(x,'/',y,'=',div(x,y))
def divent(x,y):
    try: return x//y
    except ZeroDivisionError: return 'error: denominador cero'
print(x,'división entera entre',y,'=',divent(x,y))
def modulo(x,y):
    try: return x%y
    except ZeroDivisionError: return 'error: denominador cero'
print(x,'módulo',y,'=',modulo(x,y))


Longitud de una cadena en Python

Reto: Longitud de una cadena

Crear una función que calcule la longitud de una cadena alfanumérica. Crear otra función que dada una cadena devuelva el primer caracter en mayúsculas y el resto en minúsculas. Pasar una palabra por ambas funciones y dar el resultado.




Método 1

Para calcular la longitud de una cadena lo mejor es usar len que se verá en el método 2, pero hemos querido usar aquí una forma alternativa de conseguirlo. De la misma manera para convertir una cadena en un nombre propio, existe capitalize que usaremos en el método 2, pero hemos querido ver cómo se puede conseguir sin usar esta función propia de Python. Primero usamos lower para pasar todo a minúsculas, y luego usamos upper aplicado al primer carácter para que esté mayúsculas.

def longitudCadena(x):
  contador=0
  for i in x:
    contador+=1
  return contador
def nombrePropio(x):
  y=x.lower()
  return y[0].upper()+y[1:]
x=input('Indique una palabra') or 'mADRId'
print(nombrePropio(x),'tiene',longitudCadena(x),'caracteres.')


Método 2

Usamos len para obtener la longitud del stringcapitalize para convertirlo en nombre propio. usaremos.

def longitudCadena(x):
  return len(x)
def nombrePropio(x):
  return x.capitalize()
x=input('Indique una palabra') or 'maDRid'
print(nombrePropio(x),'tiene',longitudCadena(x),'caracteres.') 

Capitalización compuesta en Python

Reto: Capitalización compuesta

Crear una aplicación que trabaje con la ley de capitalización compuesta.




Método 1

Preguntamos al usuario por el capital inicial, los años y el tipo de interés anual. Imprimimos el montante final alcanzado redondeado a dos decimales.

C=float(input('Introduzca el capital inicial') or 1000)
print('Capital inicial=',C)
n=float(input('Introduzca los años') or 3)
print('años=',n)
i=float(input('Introduzca el tipo de interés, por ejemplo 0.08 para 8%') or .08)
print('Tipo de interés anual=',i)
print('Capital final=',round(C*(1+i)**n,2))


Método 2

Generamos de forma aleatoria el capital inicial, el tiempo y el tanto de interés. Imprimimos el montante final que calcula una función.

import random
def montante(C,n,i):
  return C*(1+i)**n
C=random.randint(1000,9999)
print('Capital inicial=',C)
n=random.randint(1,10)
print('años=',n)
i=random.randint(2,20)/100
print('Tipo de interés anual=',i)
print('Capital final=',round(montante(C,n,i),2))

viernes, 13 de julio de 2018

Media ponderada

Reto: Media ponderada

Calcular la media ponderada de una serie de valores.




Vamos a calcular la media aritmética y la media ponderada de una serie de exámenes. Conocemos la nota de las prueba y su peso. Los pesos vienen dados en tanto por uno y han de sumar uno, que equivale al 100%. Hemos puesto unos datos para que diferencien bien ambas medias. La media aritmética saldrá 6,5 y la ponderara será de 8,37, ya que los pesos mayores recaen en los exámenes donde se ha obtenido mejor calificación.

Método 1

Disponemos de las notas (lista x) y de los pesos (lista w). La condición sum(w)==1 ha de arrojar el valor True, lo que permite comprobar que los pesos suman uno. Inicializamos la variable arit que calculará la media aritmética. Nos metemos en un blucle for que recorrerá todas las calificaciones de la lista x. En cada iteración ira acumulando las notas en la variable arit. Al finalizar el bucle dividimos el contenido de la variable arit entre el número de elementos de la lista x, de esta forma ya tendremos calculada la media aritmética y pasamos a imprimirla.
Inicializamos la variable pondera con el valor cero. Esta variable calculará la media ponderada. Nos metemos en un bucle for que recorrerá los números desde el cero hasta cinco, ya que la longitud de x es seis. En cada ciclo del bucle la variable pondera irá acumulando cada una de las calificaciones multiplicada por su peso en tanto por uno. Al finalizar el bucle la variable pondera ya contendrá la media aritmética ponderada que pasaremos a imprimir con un cierto redondeo.

#Notas de los exámenes
x=[7,4,9,3,6,10]
#Pesos de cada examen. Suman 1=100%
w=[.1,.05,.25,.06,.09,.45]
print('¿Los pesos suman 1?:',sum(w)==1.)
arit=0
for i in x:
  arit+=i
arit/=len(x)
print('Media aritmética:',arit)
pondera=0
for i in range(len(x)):
  pondera+=x[i]*w[i]
print('Media ponderada:',round(pondera,6))


Método 2

En este método utilizamos una notación condensada para los bucles for. Para la media aritmética el bucle for utiliza una única variable instrumental i, pero en el caso de la media ponderada son necesarias dos variable auxiliares i, j. También hemos tenido que emplear zip para unir las listas sobre las que operamos x y w.

x=[7,4,9,3,6,10] #Notas
w=[.1,.05,.25,.06,.09,.45] #Pesos
arit=round(sum(i for i in x)/len(x),6)
print('Media aritmética:',arit)
pondera=round(sum(i*j for i,j in zip(x,w)),6)
print('Media ponderada:',pondera)


Método 3

Importamos la librería científica NumPy que nos permite trabajar con vectores (arrays). Para calcular la media aritmética utilizamos mean que es una función disponible en la librería NumPy y que precisamente calcula la media aritmética de los valores que contiene la lista x.
Convertimos las listas x y w en los array xa y wa. La nota media ponderada se obtiene sin más que multiplicar ambos vectores y sumar su resultado.

import numpy as np
x=[7,4,9,3,6,10] #Notas
w=[.1,.05,.25,.06,.09,.45] #Pesos
arit=np.mean(x)
print('Media aritmética:',arit)
xa=np.array(x)
wa=np.array(w)
pondera=round(sum(xa*wa),6)
print('Media ponderada:',pondera)

martes, 10 de julio de 2018

Convertir monedas y billetes en Python

Reto: Conversión de monedas y billetes

Dada una cantidad de dinero indicar cuantos billetes y monedas de cada tipo son necesarios como mínmo.



Dado un cierto importe en euros deseamos conocer el mínimo número de monedas y billetes necesarios para alcanzar esa cifra. Disponemos de una lista con los tipos de billetes y monedas existentes, desde el billete de 500 € hasta la moneda de un céntimo (0,01 €). Son quince tipos de elementos entre billetes y monedas los que tenemos en la zona euro.

El procedimiento utilizado se basa en calcular un cociente entre la cifra inicial disponible en euros  y 500 que es el billete más grande. La parte entera nos dará el número de billetes de 500 € necesarios, y el resto se usará como denominador en la siguiente división. La segunda división se realiza dividiendo entre 200 que es el siguiente billete. La parte entera nos dará el número de billetes de 200 € necesarios y el resto se convertirá en el numerador de la siguiente división. Este proceso se sigue reiteradamente hasta llegar a la moneda más pequeña que es la de un céntimo.



Método 1

Definimos la lista T que contiene los quince tipos de billetes y monedas existentes en la zona euro. Inicializamos la lista S con quince ceros. Esta lista contendrá la salida obtenida indicando en cada uno de sus elementos el número de billetes y monedas necesarios de cada tipo para llegar a cubrir la cifra dada en euros y conseguir que sean mínimas las monedas y billetes utilizados. La lista S es la solución al caso práctico planteado.
Generamos aleatoriamente x que es la cifra en euros que vamos a descomponer. Utilizamos random.randint que únicamente nos permite generar números aleatorios enteros entre un par de ellos dados como argumentos. Si bien nosotros precisamos que la cifra en euros tenga dos decimales. Para ello, usamos un pequeño truco que consiste en dividir entre 100 el valor obtenido. De esta forma, lo que obtendremos para x son valores entre 1.000,00 € y 3.000,00 €.
En el algoritmo el primer paso usa x como numerador del cociente que iremos realizando reiteradamente, pero luego el numerador será el resto obtenido en el paso previo. Esto hace que tengamos que definir el primer resto como resto=x.

Nos metemos en un bucle for que recorre quince valores entre 0 y 14. Dentro del bucle usamos la función divmod que utiliza como argumentos el numerador y el denominador, y que devuelve dos valores que son la parte entera y el resto. Se podría haber obtenido el mismo resultado usando la división entera en Python (//) y el cálculo del módulo(%). Imprimimos S[i] que contiene el número de monedas y billetes necesarios del tipo T[i]. Al recorrer el bucle los quince elementos de estas listas lo que obtendremos por pantalla es un listado con todos los billetes y monedas necesarios de cada tipo para alcanzar la cifra inicial de x euros.



Finalmente lo que hacemos es comprobar que todos esos billetes y monedas multiplicados por el valor en euros de cada uno de los tipos resulte igual a la cifra x inicial. El último elemento a imprimir (total==x) es una condición que nos indicará con True si coinciden el total obtenido multiplicando y sumando los diferentes valores con el importe x inicial.

import random
T=[500,200,100,50,20,10,5,2,1,.5,.2,.1,.05,.02,.01]
S=[0]*15 #salida por tipo de billete y moneda
x=random.randint(100000,300000)/100
resto=x
print('Disponemos de',x,'euros.')
print('Se pueden descomponer en:')
for i in range(len(T)):
  S[i], resto = divmod(round(resto,6), T[i])
  print(int(round(S[i],4)),'de',T[i],'€')
print('Comprobación')
total=0
for i in range(len(T)):
  total+=S[i]*T[i]
total=round(total,6)
print(total,total==x)


Método 2

En este caso disponemos de la lista C de quince posiciones que contendrán el número de billetes y monedas disponibles inicialmente de cada tipo, que se generan de forma aleatoria. Esta composición de billetes y monedas, a priori no será óptima y lo que pretendemos es encontrar la composición dada por la lista de salida S que nos proporcione el número mínimo de monedas y billetes necesarios.

Dada la lista C vamos a calcular que importe total en euros supone este dinero. Para ello vamos a emplear dos procedimientos que luego podremos ver que coinciden.

  • El primer procedimiento requiere definir la variable suma que inicializamos con el valor cero. Nos metemos en un bucle for que recorrerá los quince elementos de la lista. Vamos calculando cada elemento C[i] de forma aleatoria y vamos obteniendo la suma acumulada multiplicando cada elemento i-ésimo de las listas T y C. De esta forma hemos obtenido el dinero inicialmente disponible que queda recogido en la variable suma.
  • El segundo procedimiento es mucho más sintético y no necesita definir la variable suma y no necesita hacer uso del bucle for anterior. Directamente podemos calcular x de forma condensada en una sola línea con la expresión sum([a * b for a, b in zip(T,C)]) que equivale a la función sumaproducto de Excel.
Una vez conocido el importe de los x euros lo primero que hacemos es usar un bucle for para mostrar en pantalla su composición según las diferentes monedas y billetes disponibles inicialmente, imprimiendo C[i] y T[i].



Luego imprimimos por pantalla la frase que indica nuestra intención es cambiar esas monedas y billetes por otra composición que sea mínima. Siguiendo la imagen, se puede ver la frase que dice 'Los 2692.38 € se pueden descomponer en:'. En esta frase el importe que se cita coincide con el que se muestra inicialmente, e ilustran los dos procedimientos vistos anteriormente. La primera cifra es x y la segunda es la variable suma.

El resto del algoritmo es igual que el del método anterior, salvo que al final no hacemos la comprobación que se hizo en el método 1, y que en este caso lo que hacemos es ver de cuántos billetes y monedas iniciales hemos partido y a cuantos hemos llegado. En general, se podrá apreciar una significativa reducción.


import random
T=[500,200,100,50,20,10,5,2,1,.5,.2,.1,.05,.02,.01]
C=[0]*15 #caja disponible
S=[0]*15 #salida por tipo de billete y moneda
suma=0
for i in range(15):
  C[i]=random.randint(0,5)
  suma+=T[i]*C[i]
x=sum([a * b for a, b in zip(T,C)]) #sumaproducto
print('Disponemos de',round(x,6),'euros.')
print('Están compuestos por:')
for i in range(len(T)):
  print(C[i],'de',T[i],'€')
print('Queremos cambiarlos por los mínimos billetes y monedas posibles.')
print('Los',round(suma,6),'€ se pueden descomponer en:')
resto=x
for i in range(len(T)):
  S[i], resto = divmod(round(resto,6), T[i])
  print(int(round(S[i],4)),'de',T[i],'€')
print('Teníamos',sum(C),'billestes y monedas','y los hemos reducido a',int(sum(S)))

lunes, 9 de julio de 2018

Convertir segundos en Python

Reto: Convertir segundos

Dados un cierto número se segundos expresarlos como días, horas, minutos y segundos.




Solicitamos al usuario o bien obtenemos de forma aleatoria un número de segundos totales hasta un valor máximo de dos millones. El objetivo consiste en convertirlos a un formato que nos diga cuantos días, horas, minutos y segundos contienen. Por ejemplo, 2.000.000 segundos equivalen a 23 días, 3 horas, 33 minutos y 20 segundos. Podemos ver seguidamente los cálculos en Excel.



Hemos utilizado la función int que calcula la división entera y la función mod que calcula el módulo, resto o resíduo de la división.

Método 1

En Python los cálculos son los mismos. Para hacer la división entera se usa la expresión numerador//denominador y para hacer el módulo se usa la expresión numerador%denominador, lo cual nos da el resto. También tenemso que saber que un día tiene 86.400 segundos, una hora tiene 3.600 segundos y un minuto tiene 60 segundos. Hemos tenido que usar dos variables auxiliares denominadas resto1 y resto2. Hubiera surgido también la variable resto3 pero esta no ha sido necesaria ya que finalmente este concepto coincide con el número de segundos s que quedan al final.

print('Un minuto tiene',60,'segundos')
print('Una hora tiene',60*60,'segundos')
print('Un día tiene',60*60*24,'segundos')
print('_'*28+'\n')
while True:
  x =int(input('Número de segundos: ') or 2000000)
  if x>2000000:
    print("Introduzca un valor hasta dos millones.")
  else:
    break
d=x//86400
resto1=x%86400
h=resto1//3600
resto2=resto1%3600
m=resto2//60
s=resto2%60
print( '%d días, %d horas, %d minutos, %d segundos' % \
  (d, h, m, s)))


Método 2

Con este método los segundos iniciales se obtienen de forma aleatoria hasta un máximo de dos millones. Para ir calculando la división entera y el resto hemos usaso una función que viene definida internamente en Python que se llama divmod. Esta función utiliza como argumentos el numerador y el denominador y devuelve dos valores numéricos, el primero es la división exacta y el segundo el resto. Hemos necesitado al igual que en el caso anterior dos variables auxiliares para recoger el retos1 (r1) y el resto2 (r2).

import random
x=random.randint(1,2000000)
print(x,'segundos =')
d, r1 = divmod(x, 86400)
h, r2 = divmod(r1, 3600)
m, s = divmod(r2, 60)
print(d,'días',h,'horas',m,'minutos',s,'segundos')


Frecuencias en Python

Reto: Frecuencias

Construir una lista que contenga el código de 6 aeropuertos internacionales: MAD, JFK, LHR, CDG, AMS, FRA. Generar un dado de seis caras, con las siguientes probabilidades 25%, 22%, 18%, 14%, 11%, 10%, que corresponden a cada uno de los aeropuertos respectivamente. Generar un listado de 100 aeropuertos extraídos entre los seis del array y que aparezcan de forma aleatoria cada uno según su probabilidad. Finalmente mostramos los aeropuertos y el número de veces que aparece cada uno de ellos.




Los elementos de la lista (aeropuertos) no son equiprobables. Tenemos que conseguir que salgan de forma aleatoria pero cada uno con el peso que se le ha asignado. Generamos un listado con cien aeropuertos y luego calculamos la frecuencia con la que aparece cada uno de ellos. Esas frecuencias no necesariamente han de coincidir exactamente con los pesos asignados ya que estamos trabajando en el campo de la incertidumbre.

Método 1

Importamos la libreria random para trabajar con números aleatorios. Importamos la libreria numpy para poder luego usar cumsum que nos dará las probabilidades acumuladas. Inicializamos la lista F con seis ceros. Esta lista contendrá al final las frecuencias con las que aparece cada aeropuerto. Imprimimos la lista L de aeropuertos disponibles y la lista P con las probabilidades o pesos de cada uno de ellos. Con cumsum construimos la lista A que contendrá el acumulado de las probabilidades individuales de cada aeropuerto. Imprimimos la lista de pesos acumulados A.
Definimos la función intervalo que recibe como argumentos r (un número random entre cero y uno) y A que es la lista de pesos acumulados.
Nos metemos en un bucle for para generar los cien aeropuertos. Dentro del bucle generamos un número aleatorio r  y llamamos a la función intervalo que nos devolverá un número aleatorio entre 0 y 5, pero este número ya no será equiprobable sino que estará cargado con los pesos definidos para cada aeropuerto. Ese número se llamará z y se usará como índice para obtener el aeropuerto usándolo con la lista L, así L[z]. Construiremos la lista de frecuencias con la expresión F[z]+=1 que acumulará un 1 cada vez que aparezca el aeropuerto de índice z.
Imprimimos un separador para las FRECUENCIAS. Nos metemos en un bucle for que recorre los valores 0 a 5 que es el índice que usaremos para imprimir las listas F (frecuencias), L (abreviatura del aeropuerto), C (ciudad del aeropuerto).




import random
import numpy as np
random.seed()
L=['MAD','JFK','LHR','CDG','AMS','FRA']
P=[.25,.22,.18,.14,.11,.10]
C=['Madrid','New York','London','Paris','Amsterdam','Frankfurt']
F=[0]*6 #frecuencia de cada aeropuerto
print(L)
print('probabilidad:',P)
A=np.cumsum(P) #acumulado
print('acumulada: ',A)
def intervalo(r,A):
  for i in range(len(A)):
    if r<=A[i]:
      return(i)
for j in range(100):
  r=random.random()
  z=intervalo(r,A)
  F[z]+=1
  print(L[z])
print('--- F R E C U E N C I A S ---')
for k in range(6):
  print(F[k],L[k],C[k])

También podríamos haber calculado la lista A con las probabilidades acumuladas usando las siguientes línea de código en sustitución de la expresión A=np.cumsum(P). Esto nos permitiría ahorrarnos importar la librería numpy.

A=[P[0]]*6 #probabilidad acumulada
for i in range(1,len(P)):
  A[i]=round(A[i-1]+P[i],4)


Método 2

Este método usa menos líneas de código que el anterior. Importamos de la librería random el elemento choices. Inicializamos las listas L, P y F. Esta última la inicializamos con seis valores todos ellos iguales a cero, y finalmente contendrá las frecuencias de aparción de cada aeropuerto. Nos metemos en un bucle for de cien elementos para generar todos los aeropuertos de forma aleatoria no uniforme. Con range(6) generamos una lista con los números 0 a 5. Con choices(range(6),P) lo que hacemos es elegir de forma aleatoria uno de esos seis valores numéricos de la primera lista según la probabilidad P dada por la segunda lista. Esas probabilidades actúan como los pesos o importancia relativa que tiene cada uno de los elementos a la hora de ser elegidos. La variable que obtenemos es x que contiene el elemento elegido en forma de lista. Por ejemplo, x puede resultar ser [5] que significaría que ha sido elegido el último elemento de la lista que va entre 0 y 5. Como necesitamos que ese valor no venga dado en forma de lista, sino que lo necesitamos en formato de número entero, lo consguimos con la variable y definida como y=x[0] que lo que hace es obtener el primer y único elemento de la lista x.
Imprimimos el aeropuerto usando L[y] y en el print añadimos end=' '. Eso lo que hace es evitar que se impriman los aeropuertos en vertical y deja un espacio en blanco entre ellos.
Contruimos la lista F con las frecuencias con las que se presentan cada uno de los aeropuertos. Finalmente imprimimos la lista de aeropuertos y las frecuencias asociadas. Esto se consigue usando zip que fusiona las dos listas en una sucesión de tuplas. Si intentamos imprimir el objeto zip no veríamos el resultado esperado ya que es necesario encapsularlo con alguno de estos elementos.

  • list --> lista, se ven los corchetes []. Es el sistema que hemos utilizado
  • tuple --> tupla, se vería contenido entre paréntesis ()
  • dict --> diccionario, se vería contenido entre llaves {}





from random import choices
L=['MAD','JFK','LHR','CDG','AMS','FRA']
P=[.25,.22,.18,.14,.11,.10]
F=[0]*6 #frecuencia de cada aeropuerto
print(L)
print('probabilidad:',P)
for i in range(100):
  x=choices(range(6),P)
  y=x[0]
  print(L[y], end=' ')
  F[y]+=1
print('\n','-'*25,' F R E C U E N C I A S ','-'*26)
print(list(zip(L,F)))


Método 3

Importamos el elemento choice de numpy.random. Observe que no se trata del mismo elemento que en el caso anterior. Este va en singular choice y el anterior estaba en plural choices. Incluso pertenecen a librerías diferentes. En este método y gracias al uso de choice nos ahorramos tener que construir la lista con las probabilidades acumuladas ya que ahora lo único que tenemos que hacer es proporcionar a esta función la lista L (relación de aeropuertos) y la lista P (probabilidadades individuales). La función choice nos devuelve uno de los seis aeropuertos elegido de forma aleatoria según los pesos proporcionados por la lista P de probabilidades. Con el aeropuerto z elegido vamos contruyendo una lista a con append. Como estamos dentro del bucle for la lista a finalmente contendrá cien aeropuertos que imprimiremos.
Para hacer el análisis de frecuencias usamos collections.Counter(a) que nos dará un diccionario que contiene como clave cada uno de los aeropuertos y como valor su frecuencia de aprición. Este diccionario viene ordenado de mayor a menor frecuencia de acaecimiento, por lo que no siempre veremos primero el aeropuerto de Madrid que es el más probable.




from numpy.random import choice
import collections
L=['MAD','JFK','LHR','CDG','AMS','FRA']
P=[.25,.22,.18,.14,.11,.10]
a=[] #lista que contendrá los 100 aeropuertos
for i in range(100):
  z=choice(L, p=P) #elige de una lista según pesos
  a.append(z)
print(a)
print(collections.Counter(a)) #dict con las frecuencias

viernes, 6 de julio de 2018

Juego de la tirada más larga

Reto: Juego de la tirada más larga

Cada tirada genera una sucesión de números aleatorios entre 1 y 100. La tirada finaliza cuando se obtiene un número par, entre 40 y 60. El juego lanza 20 tiradas y al final se dice que tirada ha sido la más larga. 




Método 1

Necesitaremos la variable maxi para contabilizar el número de elementos de la tirada más larga. Nos metemos en un bucle for para hacer las 20 tiradas. Dentro del bucle inicializamos la variable texto como una cadena vacía. Esta variable contendrá los números que componen una tirada. La variable n contará el número de elementos que componen una tirada. Nos metemos en un bucle while para ir generando los elementos de cada tirada. En este caso ha de ser un bucle de tipo while ya que no sabemos a priori cuan larga será la tirada. Se genera el número aleatorio x, que se integra dentro de la variable de texto. Nos econtramos con un condicional if que pretende detectar cuándo se detendrá la generación de elementos dentro de una tirada.


Si el valor de x es par y está entre 40 y 60 entonces se cumplirá la condición e imprimiremos los números de la tirada i-ésima. Nos metemos en un nuevo condicional if para anotar el número de elementos de la tirada más larga. Esto se hace con la variable maxi, y con la variable tirmax lo que hacemos es anotar en cuál de las 20 tiradas se ha alcanzado el máximo. Esta será la tirada más larga. La instrucción break hace que nos salgamos del bucle while después de haber tratado la tirada i-ésima y devuelve el flujo del programa al bucle for. Si no se cumple la condición de haber llegado a un par entre 40 y 60, esto quiere decir que necesitamos generar un nuevo número aleatorio dentro de esta misma tirada y entonces tendremso que hacer n+=1 lo cual incrementa el valor del contador en una unidad. Al final se imprime la longitud de la tirada que más elementos tiene y se indica qué tirada fue en la que se alcanzó la máxima longitud.
Este método tiene el inconveniente de que si existe empate en el máximo entre dos o más tiradas no se indican todas ellas, unicamente se imprimirá una de ellas. Esto se soluciona en el método 2.


import random
maxi=0
for i in range(1,21):
  texto=''
  n=1
  while True:
    x=random.randint(1,100)
    texto+=str(x)+' '
    if x%2==0 and x>=40 and x<=60:
      print('Tirada',i,':',texto)
      if n>=maxi:
        maxi=n
        tirmax=i
      break
    n+=1
print('El maximo nº de elementos ha sido',maxi,'y se alcanza en la tirada',tirmax)


Método 2

En este caso hemos realizado una variante del caso anterior para que recoja varias tiradas en caso en empate. En la imagen adjunta se puede ve como las tiradas 7, 15, 17 y 18 empatan en longitud puesto que todas ellas tienen 9 elementos. Hemos logrado anotarlas usando la variable tirmax como un string que va recogiendo las cadenas cuando estas llegan al máximo.
La cadena tirmax añade una coma cada vez que se agrega un número. Lo que hemos hecho es eliminar la última coma y añadir un punto para cerrar la frase. Esto se logra con la expresión siguiente.

tirmax[:len(tirmax)-2]+'.'



import random
maxi=0
tirmax='' #texto que recoge la tirada o tiradas de longitud máxima
for i in range(1,21): #generamos las tiradas 1 a 20
  texto='' #cadena que recoge los valores numéricos de una tirada
  n=1 #número de elementos que tiene cada tirada
  while True:
    x=random.randint(1,100) #aleatorio entero entre 1 y 100
    texto+=str(x)+' ' #añadimos a la frase un nuevo elemento y un espacio
    if x%2==0 and 40<=x<=60: #cuando se ha de detener la generación de números en cada tirada
      print('Tirada',i,':',texto) #se imprime la frase de la tirada i-ésima
      if n>maxi: #si el nº de elemento de esta tirada (n) es mayor que el máximo que existía hasta ahora
        maxi=n #nuevo máximo
        tirmax=str(i)+','+' ' #si tenemos nuevo máximo la frase tirmax se inicializa con el indice de la tirada actual
      elif n==maxi: #si el nº de elemento de la tirada es igual al máximo actual
        tirmax+=str(i)+','+' ' #la frase tirmax añade el indice de la tirada actual
      break #nos salimos del bucle while porque ya se ha cumplido la condición del if
    n+=1 #contador: un nuevo elemento dentro de la tirada en la que estamos
print('El maximo nº de elementos ha sido ',maxi,' y se alcanza en ',tirmax[:len(tirmax)-2]+'.')
#al final se imprime tirmax pero se quita la última coma y se añade al final un punto.


Método 3

Con el código del método 2 puede llegar a ser muy tedioso ejecutarlo varias veces hasta que se obtenga una jugada donde dos o más tiradas de lógitud máxima se den simultaneamente.  Lo que hemos hecho con este método es embeber el código en un bucle while que busca que el número de tiradas repetidas de longitud máxima sea mayor o igual a un cierto valor. En el ejemplo hemos puesto que sean cuatro las tiradas repetidas.


También hemos añadido un condicional if que consigue que si el número que se genera aleatoriamente está entre 1 y 9 se le añade un espacio vacío al imprimirle en la fila de su tirada. Con ello lo que conseguimos es que las tiradas que tengan el mismo número de elementos queden visualmente con la misma longitud. Algo similar hemos añadido para que el número de tirada entre 1 y 0 lleve un espacio previo adicional para mejorar el aspecto visual. También hemos modificado el rango de variación del número aleatorio para que se mueva entre 1 y 99. Hemos evitado el 100 porque al tener tres dígitos visualmente puede alterar la longitud del texto cuando aparece en una tirada.


import random
while True:
  maximo=0
  tirmax=''
  for i in range(1,21):
    texto=''
    n=1
    while True:
      x=random.randint(1,99)
      if x>=10:
        texto+=str(x)+' '
      else:
        texto+=' '+str(x)+' ' #añadimos un espacio previo para que visualmente quede bien
      if x%2==0 and x>=40 and x<=60:
        if i>=10:
          print('Tirada',i,':',texto)
        else: #si i está entre 1 y 9 se antecede un espacio para que visualmente quede bien
          print('Tirada ',i,':',texto)
        if n>maximo:
          maximo=n
          tirmax=str(i)+','+' '
          repes=1 #contador de tiradas repetidas de longitud máxima
        elif n==maximo:
          tirmax+=str(i)+','+' '
          repes+=1 #el contador de tiradas repetidas máximas se incrementa
        break
      n+=1
  print('El maximo nº de elementos ha sido ',maximo,' y se alcanza en ',tirmax[:len(tirmax)-2]+'.')
  if repes>=4: #queremos un mínimo de 4 tiradas de máxima longitud
    break

jueves, 5 de julio de 2018

Booleanos en Python

Reto: Booleanos

Generar aletoriamente un número del 100.000 al 200.000. Si ese número tiene un tres pierdes la partida y si carece de treses entonces has tenido éxito en el juego.



Veamos varias soluciones al juego planteado, unas usan variables booleanas y otras no, unas usan funciones y otras no, unas usan un bucle para recorrer todos los caracteres del número aleatorio y otras no. Con esta casuística de soluciones podemos aprender bastante acerda de este tipo de casos. El ejemplo es muy parecido a la programación que necesitaríamos para determinar si un número es primo o no. En ese caso la idea es suponer que de entrada el número analizado si es primo y hasta que no se encuentre alguno de los anteriores que haga que al dividir entre él de división exacta no podremos descartarlo. Por tanto, será necesario buscar si hay división exacta recorriendo unos cuantos valores previos. Y hasta que no podamos descartar que ninguno de los números previos no da división exacta no podremos afirmar que el número candidato es primo. Aquí sucede lo mismo, hasta que no se analizan los seis dígitos que componen el número aleatorio del juego, no se podrá afirmar que hemos ganado. Solo cuando hemos descartado que todos ellos son distintos de tres entonces es cuando podemos afirmar que hemos ganado.

Método 1

Vamos a jugar a 'me quiere' y 'no me quiere' como si estuviéramos desojando una margarita. Tendremos éxito cuando el número aleatorio entre cien mil y docientos mil no tenga ninguna cifra igual a tres. Si aparece algún tres entonces habremos fracasado en el juego.
Creamos una variable booleana que inicialmente tendrá el valor True. Nos metemos en un condicional if que analiza si existe algún tres en el número aleatorio. Trabajamos con cadenas alfanuméricas para que nos funcione in que busca en el string para ver si localiza algún tres. Si se cumple la condición de que ha encontrado un tres entonces la variable booleana meQuiere se torna en False.
Finalmente nos metemos en otro condicional if que analiza el valor de la variable booleana. Observe que no es necesario poner meQuiere==True, sino que para ver si esta variable es verdadera simplemente se pone la variable booleana ya que en si misma ya nos dirá si es True o False.



import random
x=str(random.randint(100000,200000))
print(x)
meQuiere=True #inicialmente me quiere
if str(3) in x:
  meQuiere=False

if meQuiere:
  print('Me quiere')
else:
  print('No me quiere')


Método 2

Generamos el número aleatorio y lo convertimos en un string. Inicializamos la variable booleana premio como True. Nos metemos en un bucle for que recorre todos los caracteres del número. Si alguno de los caracteres es igual a tres entonces la variable booleana se convierte en False y con break detenemos el bucle.
Al final nos encontramos con otro condicional if que analiza la variable booleana premio. Si es verdadera imprime que hemos ganado y si es falsa entonces habremos perdido.

import random
x=str(random.randint(100000,200000))
print(x)
premio=True #inicializamos la variable booleana como verdadera
for i in x:
  if int(i)==3: 
    premio=False
    break  

if premio:
  print('Has ganado. BIEN!!!!!!')
else:
  print('Has perdido porque ha salido un 3')


Método 3

Los métodos 3, 4 y 5 solo se diferencian en la función ganare.
Disponemos de dos funciones. La función principal se lanza llamándola con la expresión jugar(). Esta primera función no lleva argumentos, por eso dentro de los paréntesis no se escribe nada, pero es necesario ponerlos. Lo primero que hace la función jugar es generar un número aleatorio y convertirlo en string. Dentro de la función nos encontramos con un condicional if que usa como condición una llamada a la otra función que se llama ganare y la pasa un argumento que es el número aleatorio generado en forma de cadena alfanumérica. La función ganare analiza el número entregado y si contiene un tres devuleve False y si no es así devuelve True. Este retorno hace que el condicional de la función jugar actúe de forma que si el resultado es True imprimirá que hemos ganado el juego y en caso contrario nos dice que hemos perdido.
La función ganare analiza si el argumento en forma de cadena contiene un tres.

import random

#Funcion que retorna True cuando no hay ningún tres
def ganare(x):
  for i in x:
    if int(i)==3:
      return False
  return True

def jugar():
  x=str(random.randint(100000,200000))
  if ganare(x):
    print(x,' He ganado. BIEN!!!!!!')
  else:
    print(x,' He perdido porque ha salido un 3 :(')

jugar()


Método 4

Los métodos 3, 4 y 5 solo se diferencian en la función ganare.
En este método la función ganare no tiene un for que recorra todos los caracteres buscando un tres. Directamente lo que hacemos es meternos en un condicional if que pregunta si un tres como string está en x, si la respuesta es positiva retorna un False y en caso contrario retorna un True. Observe que ni siquiera hemos usado else.

import random

def ganare(x):
  if str(3) in x:
      return False
  return True

def jugar():
  x=str(random.randint(100000,200000))
  if ganare(x):
    print(x,' He ganado. BIEN!!!!!!')
  else:
    print(x,' He perdido porque ha salido un 3 :(')

jugar()


Método 5

Los métodos 3, 4 y 5 solo se diferencian en la función ganare.
Aquí si usamos una variable booleana en la función ganare. La variable se llama premio y la inicializamos en True. Si el tres como string se encuentra en el número x entonces la variable booleana se torna en False. Al final la función devuelve el valor que contenga en ese momomento la variable booleana.

import random

#Funcion que retorna True cuando no hay tres
def ganare(x):
  premio=True
  if str(3) in x:
      premio=False
  return premio

def jugar():
  x=str(random.randint(100000,200000))
  if ganare(x):
    print(x,' He ganado. BIEN!!!!!!')
  else:
    print(x,' He perdido porque ha salido un 3 :(')

jugar()


Método 6

En este caso no trabajamos con funciones. Generamos el número aleatorio lo trasnformamos en una cadena alfanumérica. Nos metemos en un bucle for que recorre todos los caracteres. Dentro del bucle tenemos un condicional if que pregunta si el caracter analizado es un tres. En caso afirmativo imprime que hemos perdido y con un break termina el bucle for. En caso contrario se imprime que hemos ganado. Lo sorprendente es la indentación de else, ya que no es la que cabría esperar a la misma altura que el if. Como vemos else está al nivel del for, y funciona. Pero no podría ser de otra forma ya que si la ponemos a la altura del if cada ver que el dígito analizado no fuera un tres nos diría que hemos ganado.

import random
x=str(random.randint(100000,200000))
for i in x:
  if int(i) == 3:
    print(x,' He perdido porque ha salido un 3.')
    break
else:
  print(x,' He ganado. Fiesta!!!')


Método 7

Este método proporciona una solución con pocas líneas de código. Generamos el número aleatorio como un string. Nos metemos en un if que se cuestiona sobre si existe algún tres. En caso afirmativo imprime que hemos ganado y en caso contrario hemos perdido. Una solución rápida y sencilla.

import random
x=str(random.randint(100000,200000))
if '3' in x:
  print(x,'Has perdido')
else:
  print(x,'Has ganado. Felicidades!!!')


Método 8

Definimos la variable texto que inicializamos con la frase 'Has ganado, porque no ha salido ningún tres.'
Nos metemos en un bucle for que recorre las seis posiciones del número aleatorio generado. Dentro del bucle tenemos un condicional que detecta si alguno de los dígitos es un tres. En caso afirmativo se reescribe la frase de la variable texto informando que ha perdido. De esta forma si no se encuentra ningún tres la frase no se reescribe y se anuncia que se ha ganado.

import random
x=str(random.randint(100000,200000))
texto='Has ganado, porque no ha salido ningún tres.'
for i in x:
  if i=='3':
    texto='Lo siento. Has perdido porque ha salido un tres.'
print(x,texto)