In [1]:
"""
IPython Notebook v4.0 para python 2.7
Librerías adicionales: Ninguna.
Contenido bajo licencia CC-BY 4.0. Código bajo licencia MIT. (c) Sebastian Flores.
"""

# Configuracion para recargar módulos y librerías 
%reload_ext autoreload
%autoreload 2

from IPython.core.display import HTML

HTML(open("style/iwi131.css", "r").read())


Out[1]:






IWI131

Programación de Computadores

Sebastián Flores

http://progra.usm.cl/

https://www.github.com/usantamaria/iwi131

Soluciones a Certamen 2, 1S 2015, Casa Central

Pregunta 1 [25%]

(a) Realice el ruteo de los siguientes programas e indique qué es lo que imprimen. Cada vez que el valor de una variable cambie, escríbalo en una nueva fila de la tabla.

Pregunta 1.b : Análisis de Algoritmo

Analice el siguiente algoritmo y determine, en pocas palabras, lo que realiza. No debe usar m ́as del espacio indicado.


In [ ]:
# n numero entero
def f(n):
    l = []
    for i in range(len(str(n))-1,-1,-1):
        x = n/(10**i)
        l.append(x)
        n=n %(10**i)
    return l

f(421)

Solución

La función coloca en una lista los dígitos del número.

Pregunta 2 [35%]

El prestamista Vito Corleone, aburrido de perseguir a sus clientes, ha solicitado la ayuda de algún astro de la programación para resolver sus problemas logísticos.

Vito cuenta con la lista clientes, la que tiene tuplas con el nombre de cada cliente, el monto adeudado y la fecha del ultimo pago (también dentro de una tupla).

clientes = [('Don Ramon', 3500, (9, 4, 2014)), 
                ('Miguel', 2785, (30, 10, 2014)), 
                ('Cesar', 100, (28, 5, 2015)), # ...
               ]

Nota: Esto es sólo un ejemplo, considere que la lista puede tener muchos clientes. Sin embargo asuma que cada nombre de cliente aparece sólo una vez.

Pregunta 2.a

Implemente la función deuda_total(clientes) que reciba como entrada la lista de tuplas clientes, y retorne la suma de las deudas de todos los deudores.

>>> deuda_total(clientes)
6385

Estrategia de solución:

  • ¿Qué estructura tienen los datos de entrada?
  • ¿Qué estructura deben tener los datos de salida?
  • ¿Cómo proceso los inputs para generar el output deseado?

In [2]:
# Cargando los datos
clientes = [('Don Ramon', 3500, (9, 4, 2014)), 
            ('Miguel', 2785, (30,10, 2014)), 
            ('Cesar', 100, (28, 5, 2015)), # ...
           ]

In [6]:
def deuda_total(clientes):
    total = 0
    for nombre, deuda, fecha in clientes:
        total += deuda
    return total

deuda_total(clientes)


Out[6]:
6385

Pregunta 2.b

Implemente la función mayor_deudor(clientes, ultimo) que retorne el nombre del cliente que tiene la mayor deuda, y que además su ultimo pago haya sido realizado en el año ultimo. Si no hay clientes con pagos en el año ultimo, retorne un string vacío.

>>> mayor_deudor(clientes, 2014)
'Don Ramon'

Estrategia de solución:

  • ¿Qué estructura tienen los datos de entrada?
  • ¿Qué estructura deben tener los datos de salida?
  • ¿Cómo proceso los inputs para generar el output deseado?

In [7]:
def mayor_deudor(clientes, ultimo):
    nombre_mayor_deudor = ""
    deuda_mayor_deudor = -float("inf")
    for nombre, deuda, (dia, mes, anno) in clientes:
        if anno==ultimo and deuda>deuda_mayor_deudor:
            nombre_mayor_deudor=nombre
            deuda_mayor_deudor=deuda
    return nombre_mayor_deudor

print mayor_deudor(clientes, 2014)
print mayor_deudor(clientes, 2015)
print mayor_deudor(clientes, 2016)


Don Ramon
Cesar

Pregunta 2.c

Implemente la función pagar(clientes, pago) que recibe la lista clientes y una tupla pago compuesta por el nombre de quien paga, el monto que cancela y la fecha en que lo hace. La función modifica y retorna la lista clientes, descontando la deuda y actualizando la fecha del ultimo pago, según se indique en la tupla pago. Si la deuda llega a 0, debe borrar al cliente de esta lista. No es necesario considerar el caso en que se paga más de lo que se debe.

>>> pagar(clientes, ('Miguel', 85, (3, 6, 2015)))
[('Don Ramon', 3500, (9, 4, 2014)), ('Miguel', 2700, (3, 6, 2015)), 
 ('Cesar', 100, (28, 5, 2015))]
>>> pagar(clientes, ('Cesar', 100, (4, 6, 2015)))
[('Don Ramon', 3500, (9, 4, 2014)), ('Miguel', 2700, (3, 6, 2015))]

Estrategia de solución:

  • ¿Qué estructura tienen los datos de entrada?
  • ¿Qué estructura deben tener los datos de salida?
  • ¿Cómo proceso los inputs para generar el output deseado?

In [8]:
# SACAR ELEMENTO DE TUPLA
tupla = ("zero", "uno","dos","tres","cuatro")
# No es posible directamente, hay que generar una nueva tupla
tupla = (tupla[0], tupla[2], tupla[3], tupla[4])
print tupla

# SACAR ELEMENTO DE LISTA
lista = ["zero", "uno","dos","tres","cuatro"]
lista.pop(1)
print lista

# SACAR ELEMENTO DE DICCIONARIO
diccio = {"zero":0, "uno":1,"dos":2,"tres":3,"cuatro":4}
del diccio["uno"]
print diccio

# SACAR ELEMENTO DE CONJUNTO
conjunto = {"zero", "uno","dos","tres","cuatro"}
conjunto.remove("uno")
print conjunto


('zero', 'dos', 'tres', 'cuatro')
['zero', 'dos', 'tres', 'cuatro']
{'cuatro': 4, 'dos': 2, 'zero': 0, 'tres': 3}
set(['cuatro', 'dos', 'tres', 'zero'])

In [9]:
def pagar(clientes, pago):
    nombre_pagador, monto_pago, fecha_pago = pago
    for i in range(len(clientes)):
        nombre, deuda, fecha = clientes[i]
        if nombre_pagador==nombre:
            deuda_restante = deuda - monto_pago
            if deuda_restante<=0:
                clientes.pop(i)
            else:
                deuda_actualizada = (nombre, deuda_restante, fecha_pago)
                clientes[i] = deuda_actualizada
    return clientes

clientes = [('Don Ramon', 3500, (9, 4, 2014)), 
            ('Miguel', 2785, (30,10, 2014)), 
            ('Cesar', 100, (28, 5, 2015)), # ...
           ]

print pagar(clientes, ('Miguel', 85, (3, 6, 2015)))
print pagar(clientes, ('Cesar', 100, (4, 6, 2015)))


[('Don Ramon', 3500, (9, 4, 2014)), ('Miguel', 2700, (3, 6, 2015)), ('Cesar', 100, (28, 5, 2015))]
[('Don Ramon', 3500, (9, 4, 2014)), ('Miguel', 2700, (3, 6, 2015))]

In [11]:
def pagar(clientes, pago):
    nombre_pagador, monto_pago, fecha_pago = pago
    for cliente in clientes:
        nombre, deuda, fecha = cliente
        if nombre_pagador==nombre:
            deuda_restante = deuda - monto_pago
            if deuda_restante<=0:
                clientes.remove(cliente)
            else:
                deuda_actualizada = (nombre, deuda_restante, fecha_pago)
                cliente = deuda_actualizada
    return clientes

clientes = [('Don Ramon', 3500, (9, 4, 2014)), 
            ('Miguel', 2785, (30,10, 2014)), 
            ('Cesar', 100, (28, 5, 2015)), # ...
           ]

print pagar(clientes, ('Miguel', 85, (3, 6, 2015)))
print pagar(clientes, ('Cesar', 100, (4, 6, 2015)))


[('Don Ramon', 3500, (9, 4, 2014)), ('Miguel', 2785, (30, 10, 2014)), ('Cesar', 100, (28, 5, 2015))]
[('Don Ramon', 3500, (9, 4, 2014)), ('Miguel', 2785, (30, 10, 2014))]

Pregunta 3 [40%]

El villano más malvado sobre la faz de la tierra, Ultron, tiene catalogado a todos los superhéroes de la tierra de la siguiente forma:

# nombre: [detalle, edad, habilidad, (min-poder, max-poder)]
    superheroes = {
    'Iron man': ['mk42', 50 , 'uni-rayo', (45, 95)],
    'Thor': ['hijo de odin', 10000 , 'mjolnir', (50, 100)],
    'Condorito':['de pelotillehue', 40, 'washington', (1, 10)],
    'Chapulin Colorado': ['no contaban con mi astucia', 40, 'chipote
    chillon', (40, 90)],
    # ...
    }
    # nombre : nombre_asociados
    asociados = {
    'Iron man': set(['Thor', 'Black Widow', 'Hawkeye', 'Hulk']),
    'Thor': set(['Iron man', 'Hulk', 'Chapulin Colorado']),
    'Condorito' : set(['Don Chuma', 'Hulk']),
    'Chapulin Colorado' : set(['Condorito', 'Thor']),
    # ...
    }

Pese a ser la inteligencia artificial más avanzada jamás creada, se le complica un poco cuando llega el momento de programar, por ello pide ayuda a los alumnos de IWI-131 en lo siguiente:


In [27]:
# CARGAR LOS DATOS

# nombre: [detalle, edad, habilidad, (min-poder, max-poder)]
superheroes = {
'Iron man': ['mk42', 50 , 'uni-rayo', (45, 95)],
'Thor': ['hijo de odin', 10000 , 'mjolnir', (50, 100)],
'Condorito':['de pelotillehue', 40, 'washington', (1, 10)],
'Chapulin Colorado': ['no contaban con mi astucia', 40, 'chipote chillon', (40, 90)],
# ...
}
# nombre : nombre_asociados
asociados = {
'Iron man': set(['Thor', 'Black Widow', 'Hawkeye', 'Hulk']),
'Thor': set(['Iron man', 'Hulk', 'Chapulin Colorado']),
'Condorito' : set(['Don Chuma', 'Hulk']),
'Chapulin Colorado' : set(['Condorito', 'Thor']),
# ...
}

Pregunta 3.a

Desarrollar la función diferencias_poder(superheroes, diferenciapoder, umbral) que reciba el diccionario superheroes, el valor diferenciapoder y un valor de umbral. La función debe retornar una lista de tuplas de todos los superhéroes que tengan una diferencia de poder (diferencia min-poder y max-poder) mayor o igual a diferencia poder y un min-poder superior al umbral. Cada tupla debe contener nombre, detalle, habilidad y max-poder.

>>> diferencias_poder(superheroes, 30, 39)
[('Iron man', 'mk42', 'uni-rayo', 95), 
('Thor', 'hijo de odin', 'mjolnir', 100), 
('Chapulin Colorado', 'no contaban con mi astucia','chipote chillon', 90)]

Estrategia de solución:

  • ¿Qué estructura tienen los datos de entrada?
  • ¿Qué estructura deben tener los datos de salida?
  • ¿Cómo proceso los inputs para generar el output deseado?

In [28]:
def diferencias_poder(superheroes, diferenciapoder, umbral):
    superheroes_seleccionados = []
    for nombre, caracteristicas in superheroes.items():
        detalle, edad, habilidad, (min_poder, max_poder) = caracteristicas
        if max_poder-min_poder>=diferenciapoder and min_poder>umbral:
            tupla_datos = (nombre, detalle, habilidad, max_poder) 
            superheroes_seleccionados.append( tupla_datos )
    return superheroes_seleccionados

diferencias_poder(superheroes, 30, 39)


Out[28]:
[('Iron man', 'mk42', 'uni-rayo', 95),
 ('Chapulin Colorado', 'no contaban con mi astucia', 'chipote chillon', 90),
 ('Thor', 'hijo de odin', 'mjolnir', 100)]

Pregunta 3.b

Ultron necesita saber quién es amigo de quién. Dos asociados se consideran amigos si cada uno tiene al otro en el diccionario asociados. Genere una función amigos(asociados) que reciba el diccionario asociados y retorne un diccionario con los amigos, donde la llave es el superhéroe y como valor un conjunto con los amigos de éste. Si un superhéroe no tiene amigos, no se agrega.

>>> amigos(asociados)
{'Iron man': set(['Thor']), 
'Chapulin Colorado': set(['Thor']), 
'Thor': set(['Iron man', 'Chapulin Colorado'])}

Estrategia de solución:

  • ¿Qué estructura tienen los datos de entrada?
  • ¿Qué estructura deben tener los datos de salida?
  • ¿Cómo proceso los inputs para generar el output deseado?

In [30]:
def amigos(asociados):
    amigos = {}
    for nombre, conjunto_socios in asociados.items():
        for nombre_socio in conjunto_socios:
            # Ver si son amigos
            if (nombre_socio in asociados) and \
               (nombre in asociados[nombre_socio]):
                # Si son amigos, agregar al diccionario
                if nombre not in amigos:
                    amigos[nombre] = set([nombre_socio])
                else:
                    amigos[nombre].add(nombre_socio)
    return amigos

print amigos(asociados)


{'Iron man': set(['Thor']), 'Chapulin Colorado': set(['Thor']), 'Thor': set(['Iron man', 'Chapulin Colorado'])}

Pregunta 3.c

Gracias a la manipulación mental de Scarlet Witch, Ultron logrará que los superhéroes amigos que posean una diferencia de poder superior a 40 y además que superen un umbral de min-poder de 30 luchen entre ellos. Se pide generar una función versus(superheroes, asociados) que reciba el diccionario superheroes, el diccionario asociados y retorne una lista de tuplas con los enfrentamientos de los amigos.

NOTA: no se deben repetir las parejas.

>>> versus(superheroes, asociados)
[('Iron man', 'Thor'), ('Chapulin Colorado', 'Thor')]

Estrategia de solución:

  • ¿Qué estructura tienen los datos de entrada?
  • ¿Qué estructura deben tener los datos de salida?
  • ¿Cómo proceso los inputs para generar el output deseado?

In [ ]:
def versus(superheroes, asociados):
    # Crear diccionario con amigos
    amigos_dict = amigos(asociados)
    # Candidatos a pelear, pero con demasiada informacion
    lista_diferencias_poder = diferencias_poder(superheroes, 30, 39)
    # Candidatos a pelear, solo nombres
    superheroes_poderosos = []
    for nombre, _, _, _ in lista_diferencias_poder:
        superheroes_poderosos.append(nombre)
    # Recorrer y agregar a lista (una unica vez)
    lista_versus = []
    for nombre_1 in superheroes_poderosos:
        for nombre_2 in amigos_dict[nombre_1]:
            if nombre_2 in superheroes_poderosos:
                tupla_a_agregar = (nombre_2, nombre_1) 
                tupla_quizas_presente = (nombre_1, nombre_2) 
                if tupla_quizas_presente not in lista_versus:
                    lista_versus.append(tupla_a_agregar)
    return lista_versus

print versus(superheroes, asociados)