La clase dict de Python proporciona muchos métodos útiles para trabajar con diccionarios.
Algunos se presentaron en el concepto de dicts.
Aquí cubrimos unos cuantos más, junto con algunas técnicas para iterar sobre diccionarios y manipularlos.
setdefault() para insertar sin erroresEl concepto de diccionarios ya explicó que .get(key, <default value>) devuelve un value existente o el default value si una key no se encuentra en un diccionario, evitando así un KeyError.
Esto funciona bien en situaciones en las que prefieres no tener un manejo de errores adicional, pero no puedes confiar en que la 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>) devuelve el value si la key se encuentra en el diccionario.
Si la key no se encuentra, inserta el par (key, default value) y devuelve el default value para su uso.
>>> 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 rellenar un diccionario a partir de un iterablePara rellenar rápidamente un diccionario con varias keys y valores por defecto, el método de clase fromkeys(iterable, <default value>) itera a través de un iterable de keys y crea un nuevo dict.
Todos los values se establecerán al 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 modificarlas.
Las vistas también son dinámicas: cuando cambian los datos subyacentes del diccionario, 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 First-in, First-out (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 Last-in, First-out (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 ordenación integrado.
Sin embargo, es posible ordenar una vista de un dict usando la función integrada sorted() con dict.items().
La vista ordenada se puede usar después para crear un nuevo diccionario.
Al igual que con la iteración, la ordenación por defecto es sobre las 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 toma los pares (key,value) de <dict_two> y los escribe 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 fusionar dicts: los operadores de union.
dict_one | dict_two crea un nuevo diccionario, formado por los pares (key, value) de dict_one y dict_two.
Cuando ambos diccionarios comparten claves, los valores 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 tanto un dict como 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 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 los diccionarios de Python.
Mecha Munch™, una empresa de automatización de la compra en supermercados, acaba de contratarte para que trabajes en su aplicación de pedidos. Tu equipo tiene la tarea de crear un MVP (producto viable mínimo) que gestione las actividades básicas del carrito de la compra y permita a los usuarios añadir, eliminar y ordenar sus pedidos de la compra. Por suerte, otro equipo se encarga de todo lo relacionado con el dinero y el pago.
El MVP debe permitir al usuario añadir artículos a su carrito de la compra. Puede tratarse de un solo artículo o de varios a la vez. Como se trata de un MVP, la cantidad de cada artículo se indica mediante repeticiones. Si un usuario quiere añadir 2 «Oranges», «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 aumentarse en 1. Si el artículo es nuevo en el carrito, debe añadirse con una cantidad de 1.
Crea la función add_item(<current_cart>, <items_to_add>), que recibe como argumentos un diccionario de carrito y cualquier iterable de artículos similar a un array.
Debe devolver un diccionario de carrito de la compra nuevo o actualizado 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}
Vaya. Parece que el equipo de producto está cayendo en el aumento incontrolado de funcionalidades. Quieren añadir funcionalidad adicional al MVP. Ahora la aplicación tiene que crear un carrito de la compra leyendo los artículos de la aplicación de notas de un usuario. Es cómodo para los usuarios, pero supone un poco más de trabajo para el equipo.
Crea la función read_notes(<notes>), que puede recibir como argumento cualquier iterable similar a un array.
La función debe analizar los artículos y crear un diccionario de carrito de la compra del usuario.
Cada artículo debe añadirse con una cantidad de 1.
Después debe devolverse 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 aplicación tiene una sección de «ideas» que está llena de recetas terminadas de distintas cocinas. El usuario puede seleccionar cualquiera de estas recetas y conseguir que todos sus ingredientes se añadan automáticamente a su carrito de la compra. El jefe de proyecto te ha pedido que crees una forma de editar estas recetas de «ideas», ya que el equipo de contenido no deja de cambiar ingredientes y 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 o 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 empezado un carrito, la aplicación le permite ordenar sus artículos alfabéticamente. Esto hace que las cosas sean más fáciles de encontrar y ayuda cuando hay errores de introducción 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 la compra y devuelve uno nuevo ordenado alfabéticamente.
>>> sort_entries({'Banana': 3, 'Apple': 2, 'Orange': 1})
{'Apple': 2, 'Banana':3, 'Orange': 1}
La aplicación tiene que enviar el carrito de un usuario determinado a la tienda para su preparación. Sin embargo, el personal de la tienda necesita saber en qué pasillo se encuentra cada artículo y si este necesita refrigeración. Así que (de forma bastante arbitraria) el «carrito de preparación» 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 la compra del usuario y un diccionario que contiene el número de pasillo de la tienda y un True/False que indica si cada artículo necesita refrigeración.
La función debe return un «carrito de preparación» combinado que contenga (cantidad, pasillo y refrigeración) para cada artículo que pide 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 aplicación no puede limitarse a cursar pedidos de clientes sin fin. Con el tiempo, la tienda se va a quedar sin diversos productos. Así que el MVP de tu aplicación 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 preparación» 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 preparación» y devolver después el inventario de la tienda actualizado.
Cuando la cantidad de un artículo de la tienda llegue a 0, dicha cantidad debe sustituirse 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.