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

¿Qué contenido aprenderemos?

  • Diccionarios: llaves (keys), valores (values), métodos y formas de iteración.

¿Porqué aprenderemos ese contenido?

  • Diccionarios: llaves (keys), valores (values), metodos y formas de iteración.

Diccionarios son una de las formas más comunes y versátiles de almacenar información.

Junto con listas, tuplas y conjuntos, completan las estructuras de almacenamiento básicas.

Son mi estructura de datos preferida.

Próximas evaluaciones

  • Vie 18 Dic 11 pm: Tarea 2
  • Lu 21 Dic 8 am: Actividad 4.
  • Lu 21 Dic 7 pm: Certamen 2
  • Lu 5 Ene 8 am: Actividad 5
  • Vie 8 Ene 3:30 pm: Certamen 3
  • Lu 18 Ene 8 am: Certamen Recuperativo

Diccionarios

Definición

El diccionario es "como una lista" excepto que:

  • En lugar de utilizar índices enteros (0,1,2,...) se puede utilizar como llave cualquier objeto inmutable en python, pero típicamente strings y tuplas.
  • El diccionario puede recibir cualquier objeto como valor.
  • No existe un orden asociado a sus elementos.

Conceptos

  • Llaves (keys): permiten acceder al contenido.
  • Valores (values): contenido accesible mediante una llave.

Diccionarios


In [3]:
d = {"alpha":1, "beta":[1,1,3,5], (0,1):"beta"}
print d # No hay orden!!


{(0, 1): 'beta', 'alpha': 1, 'beta': [1, 1, 3, 5]}

Diccionarios


In [4]:
telefonos = {'Pepito': 5552437, 'Jaimito': 5551428, 
             'Yayita': 5550012, 'NN':6626288}

In [5]:
# Paréntesis cuadrados para acceder a valores, como en listas o tuplas.
print telefonos['Jaimito']
print telefonos['Yayita']
# Funciones especiales
print "Llaves: ", telefonos.keys() # Lista de todas las llaves
print "Valores: ", telefonos.values() # Lista de todos los valores


5551428
5550012
Llaves:  ['Pepito', 'NN', 'Jaimito', 'Yayita']
Valores:  [5552437, 6626288, 5551428, 5550012]

In [7]:
#print telefonos['N'] # Llave no existe
print telefonos[5552437] # No se accede a llave por valor.


---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
<ipython-input-7-f4fcd3241008> in <module>()
      1 #print telefonos['N'] # Llave no existe
----> 2 print telefonos[5552437] # No se accede a llave por valor.

KeyError: 5552437

Diccionarios

Agregar llaves y valores


In [12]:
d = {} # Diccionario vacío: {} o dict()
d['a'] = 8
d['b'] = 5
d['c'] = 12
d['lista'] = []
print(d)
d['c'] *= -1
d['lista'].append(5)
d['d'] = 5
d['e'] = -10
d['lista'].append(8)
d['lista'] = "VACIA"
del d['e'] 
d['b'] = (d['b'], 10)
print(d)


{'a': 8, 'c': 12, 'b': 5, 'lista': []}
{'a': 8, 'c': -12, 'b': (5, 10), 'd': 5, 'lista': 'VACIA'}

Operaciones sobre diccionarios

Podemos aplicar los siguientes métodos sobre un diccionario:

  • dict.keys(): Regresa la lista de las llaves.
  • dict.values(): Regresa la lista de los valores.
  • dict.items(): Regresa una lista con todos los pares (llave, valor).
  • key in dict: Regresa un booleano que indica si la llave key ya está en las llaves del diccionario.

Operaciones sobre diccionarios

Ejemplo


In [15]:
patas = {'humano': 2, 'pulpo': 8, 'perro': 4, 'gato': 4, 'ciempies': 100}
print patas
print "patas.keys():", patas.keys()
print "patas.values():", patas.values()
print "patas.items():", patas.items()
print "list(patas):", list(patas)
print "'perro' in patas:", 'perro' in patas
print "8 in patas:", 8 in patas
print "8 in patas.values():", 8 in patas.values()
print "len(patas):", len(patas)
print "promedio patas: ", sum(patas.values()) /float(len(patas))


{'humano': 2, 'pulpo': 8, 'gato': 4, 'perro': 4, 'ciempies': 100}
patas.keys(): ['humano', 'pulpo', 'gato', 'perro', 'ciempies']
patas.values(): [2, 8, 4, 4, 100]
patas.items(): [('humano', 2), ('pulpo', 8), ('gato', 4), ('perro', 4), ('ciempies', 100)]
list(patas): ['humano', 'pulpo', 'gato', 'perro', 'ciempies']
'perro' in patas: True
8 in patas: False
8 in patas.values(): True
len(patas): 5
promedio patas:  23.6

Ejercicio: contar letras

Escriba una función contrar_letras(palabra) que reciba un string y retorne un diccionario que indique cuantas veces aparece cada letra en el string. Por ejemplo:

  • contar_letras('entretener') debería regresar {'e': 4, 'n': 2, 'r': 2, 't': 2}
  • contar_letras('lapiz') debería regresar {'a': 1, 'i': 1, 'l': 1, 'p': 1, 'z': 1}

In [17]:
def contar_letras(palabra):
    # Inicializar diccionario vacío
    letras={}
    # Recorrer las letras de la palabra
    for c in palabra:
        if not c in letras:
            letras[c]=1
        else:
            letras[c]+=1
    # Para cada letra, ver si no está inicializar (=0) y/o aumentar (+=1)
    # Regresar el resultado
    return letras 

# Verificacion
print(contar_letras('entretener')) # {'n': 2, 'e': 4,'r': 2, 't': 2}
print(contar_letras('lapiz')) #  {'a': 1, 'i': 1, 'l': 1, 'p': 1, 'z': 1}


{'r': 2, 'e': 4, 't': 2, 'n': 2}
{'a': 1, 'p': 1, 'i': 1, 'l': 1, 'z': 1}

Ejercicio: contar letras

Escriba una función contrar_letras(palabra) que reciba un string y retorne un diccionario que indique cuantas veces aparece cada letra en el string. Por ejemplo:

  • contar_letras('entretener') debería regresar {'e': 4, 'n': 2, 'r': 2, 't': 2}
  • contar_letras('lapiz') debería regresar {'a': 1, 'i': 1, 'l': 1, 'p': 1, 'z': 1}

In [19]:
# Solución
def contar_letras(palabra):
    # Inicializar diccionario vacío
    cuentas = {}
    # Recorrer las letras de la palabra
    for letra in palabra:
        # Para cada letra, ver si no está inicializar (=0) y/o aumentar (+=1)
        if letra not in cuentas:
            cuentas[letra] = 0
        cuentas[letra] = cuentas[letra] + 1
    # Regresar el resultado
    return cuentas

# Verificacion
print(contar_letras('entretener')) # {'n': 2, 'e': 4,'r': 2, 't': 2}
print(contar_letras('lapiz')) #  {'a': 1, 'i': 1, 'l': 1, 'p': 1, 'z': 1}


---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
<ipython-input-19-f7d6f8fe531b> in <module>()
     13 
     14 # Verificacion
---> 15 print(contar_letras('entretener')) # {'n': 2, 'e': 4,'r': 2, 't': 2}
     16 print(contar_letras('lapiz')) #  {'a': 1, 'i': 1, 'l': 1, 'p': 1, 'z': 1}

<ipython-input-19-f7d6f8fe531b> in contar_letras(palabra)
      8         #if letra not in cuentas:
      9         #    cuentas[letra] = 0
---> 10         cuentas[letra] = cuentas[letra] + 1
     11     # Regresar el resultado
     12     return cuentas

KeyError: 'e'

Notar que los diccionarios no tienen orden. La primera letra ingresada no es la primera letra que se muestra.

Recorrer diccionarios

Es posible utilizar un ciclo for sobre un diccionario de diversas maneras:


In [20]:
# Manera directa, sobre las llaves
capitales = {'Chile': 'Santiago', 'Peru': 'Lima', 'Ecuador': 'Quito',}
for pais in capitales:
    print('La capital de '+pais+' es '+capitales[pais])


La capital de Ecuador es Quito
La capital de Peru es Lima
La capital de Chile es Santiago

In [23]:
# Manera indirecta, sólo sobre los valores
for capital in capitales.values():
    print capital,' es una linda ciudad'


Quito  es una linda ciudad
Lima  es una linda ciudad
Santiago  es una linda ciudad

In [22]:
# Simultáneamente sobre llaves y valores
for pais, capital in capitales.items():
    print(capital+' es la capital de '+pais)


Quito es la capital de Ecuador
Lima es la capital de Peru
Santiago es la capital de Chile

Diccionarios

Otro ejercicio

Dadas 4 listas de nombres, apellidos, rol y carrera, escriba una función que entregue un diccionario que a cada rol asigne una tupla con nombre completo y carrera:

roles = ["2004001-7", "2004007-3", "007-K"]
nombres = ["Sebastian", "Maria Jose", "James"]
apellidos = ["Flores", "Vargas", "Bond"]
carreras = ["ICM", "ICI", "AS"]

print diccionarizame(roles, nombres, apellidos, carrera)

{'2004007-3': ('Maria Jose Vargas','ICI'), 
'007-K': ('James Bond', 'AS'),
'2004001-7': ('Sebastian Flores', 'ICM')}

In [24]:
def diccionarizame(roles, nombres, apellidos, carreras):
    # FIX ME
    dic = {}
    for i in range(len(roles)):
        rol = roles[i]
        nombre = nombres[i]
        apellido = apellidos[i]
        carrera = carreras[i]
        nombre_completo = nombre +' '+ apellido
        dic[rol] = (nombre_completo, carrera)
        
    return dic

roles = ["2004001-7", "2004007-3", "007-K"]
nombres = ["Sebastian", "Maria Jose", "James"]
apellidos = ["Flores", "Vargas", "Bond"]
carreras = ["ICM", "ICI", "AS"]

print diccionarizame(roles, nombres, apellidos, carreras)


{'2004007-3': ('Maria Jose Vargas', 'ICI'), '007-K': ('James Bond', 'AS'), '2004001-7': ('Sebastian Flores', 'ICM')}

In [ ]:
# Solucion
def diccionarizame(roles, nombres, apellidos, carreras):
    d = {}
    for i in range(len(roles)):
        rol = roles[i]
        nombre = nombres[i] + " " + apellidos[i]
        carrera = carreras[i]
        d[rol] = (nombre, carrera)
    return d

roles = ["2004001-7", "2004007-3", "007-K"]
nombres = ["Sebastian", "Maria Jose", "James"]
apellidos = ["Flores", "Vargas", "Bond"]
carreras = ["ICM", "ICI", "AS"]

print diccionarizame(roles, nombres, apellidos, carreras)

Diccionarios

Ejercicio Clásico

Escriba una función invertir(d) que entregue un diccionario cuyas llaves sean los valores de d y cuyos valores sean las llaves respectivas:

print invertir({1: 2, 3: 4, 5: 6})
{2: 1, 4: 3, 6: 5}

apodos = {
          'Suazo': 'Chupete',
          'Sanchez': 'Maravilla',
          'Medel': 'Pitbull',
          'Valdivia': 'Mago',
         }
print invertir(apodos)
{'Maravilla': 'Sanchez', 'Mago': 'Valdivia', 
'Chupete': 'Suazo', 'Pitbull': 'Medel'}

In [26]:
def invertir(d):
    # FIX ME
    p = {}
    for llave, valor in d.items():
        p[valor] = llave
    return p
    
print invertir({1: 2, 3: 4, 5: 6})
apodos = {
          'Suazo': 'Chupete',
          'Sanchez': 'Maravilla',
          'Medel': 'Pitbull',
          'Valdivia': 'Mago',
         }
print invertir(apodos)


{2: 1, 4: 3, 6: 5}
{'Maravilla': 'Sanchez', 'Mago': 'Valdivia', 'Chupete': 'Suazo', 'Pitbull': 'Medel'}

In [ ]:
# Solución
def invertir(d):
    d_inv = {}
    for k,v in d.items():
        d_inv[v] = k
    return d_inv
    
print invertir({1: 2, 3: 4, 5: 6})
apodos = {
          'Suazo': 'Chupete',
          'Sanchez': 'Maravilla',
          'Medel': 'Pitbull',
          'Valdivia': 'Mago',
         }
print invertir(apodos)

Diccionarios

Ejercicio Clásico 2

Escriba una función maximo(d) que entregue la llave del valor máximo del diccionario.

print maximo({"uno":1, "dos": 2,
              "tres":3, "mil":1000,
              "infinito":float("inf")})
"infinito"

In [ ]:
def maximo(d):
    # FIX ME
    return

numeros = {"uno":1, "dos": 2, "tres":3, "mil":1000, "infinito":float("inf")}
k = maximo(numeros)
print k
print numeros[k]

In [27]:
def maximo(d):
    key_max = ""
    val_max = -float("inf")
    for key, val in d.items():
        if  val>val_max:
            key_max = key
            val_max = val
    return key_max

numeros = {"uno":1, "dos": 2, "tres":3, "mil":1000, "infinito":float("inf")}
k = maximo(numeros)
print k
print numeros[k]


infinito
inf

Consejo

¡Practicar, practicar, practicar!

  • Problemas de las guías.
  • Certámenes anteriores.

Ejercicio Certamen Tipo

La red social bookface almacena la información de sus usuarios en un diccionario. Las llaves son un código numérico entero asignado a cada usuario, y los valores son tuplas con el nombre, la ciudad y la fecha de nacimiento del usuario. La fecha de nacimiento es una tupla (año, mes, día):


In [29]:
usuarios = {
522514: ('Jean Dupont', 'Marseille', (1989, 11, 21)),
587125: ('Perico Los Palotes', 'Valparaiso', (1990, 4, 12)),
587126: ('Mauricio Isla', 'Marseille', (1988, 6, 12)),
189471: ('Jan Kowalski', 'Krakov', (1994, 4, 22)),
914210: ('Antonio Nobel', 'Valparaiso', (1988, 7, 1)),
# ...
}

Ejercicio Certamen Tipo

Misma ciudad

a) Escriba la función misma_ciudad(u1, u2), que indique si los usuarios con códigos u1 y u2 viven en la misma ciudad.

print misma_ciudad(914210, 587125)
True
print misma_ciudad(522514, 189471)
False

In [30]:
def misma_ciudad(u1,u2):
    # FIX ME
    nombre1,ciudad1,fecha1=usuarios[u1]
    nombre2,ciudad2,fecha2=usuarios[u2]
    return ciudad1==ciudad2

print misma_ciudad(914210, 587125)
print misma_ciudad(522514, 189471)


True
False

In [31]:
def misma_ciudad(u1,u2):
    return usuarios[u1][1]==usuarios[u2][1]

print misma_ciudad(914210, 587125)
print misma_ciudad(522514, 189471)


True
False

Ejercicio Certamen Tipo

Diferencia Edad

b) Escriba la función diferencia_edad(u1, u2), que retorne la diferencia de edad entre los usuarios cuyos códigos son u1 y u2.

Utilice sólo el año de nacimiento de los usuarios para calcular la diferencia, no el mes ni el día.


In [ ]:
def diferencia_edad(u1,u2):
    # FIX ME
    return

print diferencia_edad(914210, 587125)
print diferencia_edad(522514, 189471)

In [ ]:
def diferencia_edad(u1,u2):
    name1,city1,(year1,month1,day1) = usuarios[u1]
    name2,city2,(year2,month2,day2) = usuarios[u2]
    return abs(year1-year2)

print diferencia_edad(914210, 587125)
print diferencia_edad(522514, 189471)

Ejercicio Certamen Tipo

Continuación

Para guardar la información sobre cuáles de sus usuarios son amigos entre sí, BookFace utiliza el conjunto amistades, que contiene tuplas con los códigos de dos usuarios. Si la tupla (a, b) está dentro del conjunto, significa que los usuarios con códigos a y b son amigos. En todas las tuplas se cumple que $a<b$ (la tupla aparece una única vez).


In [ ]:
amistades = [ (522514, 914210), 
              (587125, 914210), 
              (587126, 914210), 
              (189471, 587125), # ...
            ]

Ejercicio Certamen Tipo

Obtener amigos

a) Escriba la función obtener_amigos(u), que retorne una lista con los códigos de los amigos de u.


In [ ]:
def obtener_amigos(u):
    # FIX ME
    return

print obtener_amigos(914210)

In [ ]:
def obtener_amigos(u):
    amigos = []
    for v,w in amistades:
        if v==u:
            amigos.append(w)
        if w==u:
            amigos.append(v)
    return amigos

print obtener_amigos(914210)

Ejercicio Certamen Tipo

Obtener amigos

b) Escriba la función recomendar_amigos(u), que retorne una lista con los código de los usuarios que cumplen todas estas condiciones a la vez:

  • Son amigos de un amigo de u,
  • No son amigos de u,
  • Viven en la misma ciudad que u, y
  • Tienen menos de diez años de diferencia con u.

In [ ]:
def recomendar_amigos(u):
    # FIX ME
    return

recomendar_amigos(522514)

In [ ]:
def recomendar_amigos(u):
    amigos_actuales = obtener_amigos(u)
    nuevos_amigos = []
    for amigo in amigos_actuales:
        for candidato in obtener_amigos(amigo):
            bool_ciudad = misma_ciudad(u, candidato)
            bool_edad = ( diferencia_edad(u,candidato) < 10)
            bool_no_amigos = ( candidato not in amigos_actuales)
            bool_no_mismo = ( candidato != u )
            if bool_ciudad and bool_edad and bool_no_amigos and bool_no_mismo:
                nuevos_amigos.append(candidato)
    return nuevos_amigos

codigos = recomendar_amigos(522514)
for c in codigos:
    print usuarios[c]