La clase dict de Python ofrece muchos métodos útiles para trabajar con diccionarios.
Algunos se presentaron en el concepto de dicts.
Aquí cubrimos algunos más, junto con algunas técnicas para iterar y manipular diccionarios.
setdefault() para insertar sin erroresEl concepto de diccionarios ya explicaba que .get(key, <default value>) devuelve un value existente o el default value si no se encuentra un key en el diccionario, y así evita un KeyError.
Esto funciona bien en situaciones en las que prefieres no tener manejo de errores adicional, pero no puedes confiar en que el key que buscas esté presente.
Para una operación de inserción igualmente «segura» (sin KeyError), existe el método .setdefault(key, <default value>).
setdefault(key, <default value>) devolverá el value si el key se encuentra en el diccionario.
Si no se encuentra el key, insertará el par (key, default value) y devolverá el default value para que lo uses.
>>> palette_I = {'Grassy Green': '#9bc400', 'Purple Mountains Majesty': '#8076a3', 'Misty Mountain Pink': '#f9c5bd'}
# Looking for the value associated with key "Rock Brown".
# The key does not exist, so it is added with the default value, and the value is returned.
>>> palette_I.setdefault('Rock Brown', '#694605')
'#694605'
# The (key, default value) pair has now been added to the dictionary.
>>> palette_I
{'Grassy Green': '#9bc400', 'Purple Mountains Majesty': '#8076a3', 'Misty Mountain Pink': '#f9c5bd', 'Rock Brown': '#694605'}
fromkeys() para poblar un diccionario a partir de un iterablePara poblar rápidamente un diccionario con varios keys y valores predeterminados, el método de clase fromkeys(iterable, <default value>) recorrerá un iterable de keys y creará un nuevo dict.
Todos los values se establecerán en el default value proporcionado:
>>> new_dict = dict.fromkeys(['Grassy Green', 'Purple Mountains Majesty', 'Misty Mountain Pink'], 'fill in hex color here')
{'Grassy Green': 'fill in hex color here',
'Purple Mountains Majesty': 'fill in hex color here',
'Misty Mountain Pink': 'fill in hex color here'}
Los métodos .keys(), .values() y .items() devuelven vistas iterables de un diccionario.
Estas vistas se pueden usar para recorrer fácilmente las entradas sin alterarlas.
Las vistas también son dinámicas: cuando los datos subyacentes del diccionario cambian, el view object asociado refleja el cambio:
>>> palette_I = {'Grassy Green': '#9bc400',
'Purple Mountains Majesty': '#8076a3',
'Misty Mountain Pink': '#f9c5bd'}
# Using .keys() returns a list of keys.
>>> palette_I.keys()
dict_keys(['Grassy Green', 'Purple Mountains Majesty', 'Misty Mountain Pink'])
# Using .values() returns a list of values.
>>> palette_I.values()
dict_values(['#9bc400', '#8076a3', '#f9c5bd'])
# Using .items() returns a list of (key, value) tuples.
>>> palette_I.items()
dict_items([('Grassy Green', '#9bc400'), ('Purple Mountains Majesty', '#8076a3'), ('Misty Mountain Pink', '#f9c5bd')])
# Views are dynamic. Changing values in the dict changes all of the associated views.
>>> palette_I['Purple Mountains Majesty'] = (128, 118, 163)
>>> palette_I['Deep Red'] = '#932432'
>>> palette_I.values()
dict_values(['#9bc400', (128, 118, 163), '#f9c5bd', '#932432'])
>>> palette_I.keys()
dict_keys(['Grassy Green', 'Purple Mountains Majesty', 'Misty Mountain Pink', 'Deep Red'])
>>> palette_I.items()
dict_items([('Grassy Green', '#9bc400'), ('Purple Mountains Majesty', (128, 118, 163)), ('Misty Mountain Pink', '#f9c5bd'), ('Deep Red', '#932432')])
.keys(), .values() y .items()
En Python 3.7+, los dicts conservan el orden en que se insertan las entradas, lo que permite una iteración primero en entrar, primero en salir (FIFO) al usar .keys(), .values() o .items().
En Python 3.8+, las vistas también son reversibles.
Esto permite iterar claves, valores o pares (key, value) en orden último en entrar, primero en salir (LIFO) usando reversed(<dict>.keys()), reversed(<dict>.values()) o reversed(<dict>.items()):
>>> palette_II = {'Factory Stone Purple': '#7c677f', 'Green Treeline': '#478559', 'Purple baseline': '#161748'}
# Iterating in insertion order (First in, first out)
>>> for item in palette_II.items():
... print(item)
...
('Factory Stone Purple', '#7c677f')
('Green Treeline', '#478559')
('Purple baseline', '#161748')
# Iterating in the reverse direction. (Last in, first out)
>>> for item in reversed(palette_II.items()):
... print (item)
...
('Purple baseline', '#161748')
('Green Treeline', '#478559')
('Factory Stone Purple', '#7c677f')
Los diccionarios no tienen un método de ordenamiento integrado.
Sin embargo, es posible ordenar una vista de dict usando la función integrada sorted() junto con dict.items().
La vista ordenada se puede usar luego para crear un nuevo diccionario.
Al igual que con la iteración, el orden predeterminado se basa en los keys del diccionario.
# Default ordering for a dictionary is insertion order (First in, first out).
>>> color_palette = {'Grassy Green': '#9bc400',
'Purple Mountains Majesty': '#8076a3',
'Misty Mountain Pink': '#f9c5bd',
'Factory Stone Purple': '#7c677f',
'Green Treeline': '#478559',
'Purple baseline': '#161748'}
# The default sort order for a dictionary uses the keys.
>>> sorted_palette = dict(sorted(color_palette.items()))
>>> sorted_palette
{'Factory Stone Purple': '#7c677f',
'Grassy Green': '#9bc400',
'Green Treeline': '#478559',
'Misty Mountain Pink': '#f9c5bd',
'Purple Mountains Majesty': '#8076a3',
'Purple baseline': '#161748'}
.update()
<dict_one>.update(<dict_two>) se puede usar para combinar dos diccionarios.
Este método tomará los pares (key,value) de <dict_two> y los escribirá en <dict_one>:
>>> palette_I = {'Grassy Green': '#9bc400',
'Purple Mountains Majesty': '#8076a3',
'Misty Mountain Pink': '#f9c5bd'}
>>> palette_II = {'Factory Stone Purple': '#7c677f',
'Green Treeline': '#478559',
'Purple Baseline': '#161748'}
>>> palette_I.update(palette_II)
# Note that new items from palette_II are added.
>>> palette_I
{'Grassy Green': '#9bc400', 'Purple Mountains Majesty': '#8076a3', 'Misty Mountain Pink': '#f9c5bd', 'Factory Stone Purple': '#7c677f', 'Green Treeline': '#478559', 'Purple Baseline': '#161748'}
Cuando las claves de los dos diccionarios coinciden, el value de dict_one se sobrescribe con el value correspondiente de dict_two:
>>> palette_I = {'Grassy Green': '#9bc400', 'Purple Mountains Majesty': '#8076a3', 'Misty Mountain Pink': '#f9c5bd',
'Factory Stone Purple': '#7c677f', 'Green Treeline': '#478559', 'Purple baseline': '#161748'}
>>> palette_III = {'Grassy Green': (155, 196, 0), 'Purple Mountains Majesty': (128, 118, 163),
'Misty Mountain Pink': (249, 197, 189)}
>>> palette_I.update(palette_III)
# Overlapping values in palette_I are replaced with values from palette_III
>>> palette_I
{'Grassy Green': (155, 196, 0),
'Purple Mountains Majesty': (128, 118, 163),
'Misty Mountain Pink': (249, 197, 189),
'Factory Stone Purple': '#7c677f',
'Green Treeline': '#478559', 'Purple baseline': '#161748'}
| y |=)Python 3.9 introduce otra forma de combinar dicts: los operadores de union.
dict_one | dict_two creará un nuevo diccionario, formado por los pares (key, value) de dict_one y dict_two.
Cuando ambos diccionarios comparten claves, los values de dict_two tienen prioridad.
>>> palette_I = {'Grassy Green': '#9bc400', 'Purple Mountains Majesty': '#8076a3', 'Misty Mountain Pink': '#f9c5bd'}
>>> palette_II = {'Factory Stone Purple': '#7c677f', 'Green Treeline': '#478559', 'Purple baseline': '#161748'}
>>> new_dict = palette_I | palette_II
>>> new_dict
...
{'Grassy Green': '#9bc400',
'Purple Mountains Majesty': '#8076a3',
'Misty Mountain Pink': '#f9c5bd',
'Factory Stone Purple': '#7c677f',
'Green Treeline': '#478559',
'Purple baseline': '#161748'}
dict_one |= other se comporta de forma similar a <dict_one>.update(<other>), pero en este caso, other puede ser un dict o un iterable de pares (key, value):
>>> palette_III = {'Grassy Green': (155, 196, 0),
'Purple Mountains Majesty': (128, 118, 163),
'Misty Mountain Pink': (249, 197, 189)}
>>> new_dict |= palette_III
>>> new_dict
...
{'Grassy Green': (155, 196, 0),
'Purple Mountains Majesty': (128, 118, 163),
'Misty Mountain Pink': (249, 197, 189),
'Factory Stone Purple': '#7c677f',
'Green Treeline': '#478559',
'Purple baseline': '#161748'}
Para obtener una explicación detallada de los diccionarios y de los métodos para trabajar con ellos, el tutorial oficial y la referencia oficial de la biblioteca son excelentes puntos de partida.
Real Python y Finxter también tienen artículos muy completos sobre diccionarios de Python.
Mecha Munch™, una empresa de automatización de compras de supermercado, acaba de contratarte para trabajar en su app de pedidos. Tu equipo tiene la tarea de construir un MVP (producto mínimo viable) que gestione todas las actividades básicas del carrito de compras, permitiendo a los usuarios agregar, eliminar y ordenar sus pedidos de supermercado. ¡Por suerte, otro equipo se encarga de todo el dinero y las funciones de pago!
El MVP debería permitir al usuario agregar artículos a su carrito de compras. Puede ser un solo artículo o varios a la vez. Como se trata de un MVP, la cantidad de artículos se indica con repeticiones. Si un usuario quiere agregar 2 naranjas, 'Oranges' aparecerá dos veces en el iterable de entrada. Si el usuario ya tiene el artículo en su carrito, la cantidad del carrito debe aumentar en 1. Si el artículo es nuevo en el carrito, se debe agregar con una cantidad de 1.
Crea la función add_item(<current_cart>, <items_to_add>) que recibe como argumentos un diccionario del carrito y cualquier iterable tipo lista de artículos para agregar.
Debe devolver un diccionario nuevo/actualizado del carrito de compras para el usuario.
>>> add_item({'Banana': 3, 'Apple': 2, 'Orange': 1},
('Apple', 'Apple', 'Orange', 'Apple', 'Banana'))
{'Banana': 4, 'Apple': 5, 'Orange': 2}
>>> add_item({'Banana': 3, 'Apple': 2, 'Orange': 1},
['Banana', 'Orange', 'Blueberries', 'Banana'])
{'Banana': 5, 'Apple': 2, 'Orange': 2, 'Blueberries': 1}
Ups. Parece que el equipo de producto está incurriendo en un exceso de funcionalidades. Quieren agregar funcionalidad extra al MVP. Ahora la aplicación tiene que crear un carrito de compras leyendo los artículos de la app de notas de un usuario. Es cómodo para los usuarios, pero un poco más de trabajo para el equipo.
Crea la función read_notes(<notes>) que puede recibir como argumento cualquier iterable tipo lista.
La función debe analizar los artículos y crear un carrito/diccionario de compras del usuario.
Cada artículo se debe agregar con una cantidad de 1.
Luego se debe devolver el nuevo carrito del usuario.
>>> read_notes(('Banana','Apple', 'Orange'))
{'Banana': 1, 'Apple': 1, 'Orange': 1}
>>> read_notes(['Blueberries', 'Pear', 'Orange', 'Banana', 'Apple'])
{'Blueberries' : 1, 'Pear' : 1, 'Orange' : 1, 'Banana' : 1, 'Apple' : 1}
La app tiene una sección de «ideas» que se llena con recetas terminadas de varias cocinas. El usuario puede seleccionar cualquiera de estas recetas y hacer que todos sus ingredientes se agreguen automáticamente a su carrito de compras. El gerente del proyecto te ha pedido que crees una forma de editar estas recetas de «ideas», ya que el equipo de contenido cambia constantemente los ingredientes y las cantidades.
Crea la función update_recipes(<ideas>, <recipe_updates>) que recibe como argumentos un diccionario de «ideas» y un iterable de actualizaciones de recetas.
La función debe devolver el diccionario de «ideas» nuevo/actualizado.
>>>update_recipes(
{'Banana Bread' : {'Banana': 1, 'Apple': 1, 'Walnuts': 1, 'Flour': 1, 'Eggs': 2, 'Butter': 1},
'Raspberry Pie' : {'Raspberry': 1, 'Orange': 1, 'Pie Crust': 1, 'Cream Custard': 1}},
(('Banana Bread', {'Banana': 4, 'Walnuts': 2, 'Flour': 1, 'Butter': 1, 'Milk': 2, 'Eggs': 3}),)
)
...
{'Banana Bread': {'Banana': 4, 'Walnuts': 2, 'Flour': 1, 'Butter': 1, 'Milk': 2, 'Eggs': 3},
'Raspberry Pie': {'Raspberry': 1, 'Orange': 1, 'Pie Crust': 1, 'Cream Custard': 1}}
>>> update_recipes(
{'Banana Bread' : {'Banana': 1, 'Apple': 1, 'Walnuts': 1, 'Flour': 1, 'Eggs': 2, 'Butter': 1},
'Raspberry Pie' : {'Raspberry': 1, 'Orange': 1, 'Pie Crust': 1, 'Cream Custard': 1},
'Pasta Primavera': {'Eggs': 1, 'Carrots': 1, 'Spinach': 2, 'Tomatoes': 3, 'Parmesan': 2, 'Milk': 1, 'Onion': 1}},
[('Raspberry Pie', {'Raspberry': 3, 'Orange': 1, 'Pie Crust': 1, 'Cream Custard': 1, 'Whipped Cream': 2}),
('Pasta Primavera', {'Eggs': 1, 'Mixed Veggies': 2, 'Parmesan': 2, 'Milk': 1, 'Spinach': 1, 'Bread Crumbs': 1}),
('Blueberry Crumble', {'Blueberries': 2, 'Whipped Creme': 2, 'Granola Topping': 2, 'Yogurt': 3})]
)
...
{'Banana Bread': {'Banana': 1, 'Apple': 1, 'Walnuts': 1, 'Flour': 1, 'Eggs': 2, 'Butter': 1},
'Raspberry Pie': {'Raspberry': 3, 'Orange': 1, 'Pie Crust': 1, 'Cream Custard': 1, 'Whipped Cream': 2},
'Pasta Primavera': {'Eggs': 1, 'Mixed Veggies': 2, 'Parmesan': 2, 'Milk': 1, 'Spinach': 1, 'Bread Crumbs': 1},
'Blueberry Crumble': {'Blueberries': 2, 'Whipped Creme': 2, 'Granola Topping': 2, 'Yogurt': 3}}
Una vez que un usuario ha iniciado un carrito, la app le permite ordenar sus artículos alfabéticamente. Esto hace que sea más fácil encontrarlos, y ayuda cuando hay errores de ingreso de datos, como tener 'potatoes' y 'Potato' en la base de datos.
Crea la función sort_entries(<cart>) que recibe como argumento un carrito/diccionario de compras y devuelve uno nuevo, ordenado alfabéticamente.
>>> sort_entries({'Banana': 3, 'Apple': 2, 'Orange': 1})
{'Apple': 2, 'Banana':3, 'Orange': 1}
La app necesita enviar el carrito de un usuario dado a la tienda para su surtido. Sin embargo, los encargados de la tienda necesitan saber en qué pasillo de la tienda se puede encontrar el artículo y si este necesita refrigeración. Así que (de forma bastante arbitraria) el «carrito de surtido» debe ordenarse en orden alfabético inverso, combinando las cantidades de los artículos con la información de ubicación y refrigeración.
Crea la función send_to_store(<cart>, <aisle_mapping>) que recibe un carrito de compras del usuario y un diccionario que tiene el número de pasillo de la tienda y un True/False para indicar si cada artículo necesita refrigeración.
La función debe return un «carrito de surtido» combinado que tenga (cantidad, pasillo y refrigeración) para cada artículo que ordena el cliente.
Los artículos deben aparecer en orden alfabético inverso.
>>> send_to_store({'Banana': 3, 'Apple': 2, 'Orange': 1, 'Milk': 2},
{'Banana': ['Aisle 5', False], 'Apple': ['Aisle 4', False], 'Orange': ['Aisle 4', False], 'Milk': ['Aisle 2', True]})
{'Orange': [1, 'Aisle 4', False], 'Milk': [2, 'Aisle 2', True], 'Banana': [3, 'Aisle 5', False], 'Apple': [2, 'Aisle 4', False]}
La app no puede simplemente hacer pedidos de clientes sin parar. Con el tiempo, a la tienda se le van a acabar varios productos. Así que tu MVP de la app necesita actualizar el inventario de la tienda cada vez que un usuario envía su pedido a la tienda. De lo contrario, los clientes pedirán productos que en realidad no están disponibles.
Crea la función update_store_inventory(<fulfillment_cart>, <store_inventory>) que recibe un «carrito de surtido» y un inventario de la tienda.
La función debe reducir las cantidades del inventario de la tienda según el número «pedido» en el «carrito de surtido» y luego devolver el inventario de la tienda actualizado.
Cuando la cantidad de un artículo de la tienda llega a 0, la cantidad debe reemplazarse por el mensaje «Out of Stock».
>>> update_store_inventory({'Orange': [1, 'Aisle 4', False], 'Milk': [2, 'Aisle 2', True], 'Banana': [3, 'Aisle 5', False], 'Apple': [2, 'Aisle 4', False]},
{'Banana': [15, 'Aisle 5', False], 'Apple': [12, 'Aisle 4', False], 'Orange': [1, 'Aisle 4', False], 'Milk': [4, 'Aisle 2', True]})
{'Banana': [12, 'Aisle 5', False], 'Apple': [10, 'Aisle 4', False], 'Orange': ['Out of Stock', 'Aisle 4', False], 'Milk': [2, 'Aisle 2', True]}
Regístrate en Exercism para aprender y dominar Python con 17 conceptos146 ejercicios y mentoría humana real, todo gratis.