Header Ads Widget

Ticker

6/recent/ticker-posts

Cómo recorrer un diccionario en Python: claves, valores y más

Bienvenido a otro artículo de Cómo usar Python. Hoy, analizaremos los diccionarios que parece ser un tema candente, al menos desde un punto de vista orgánico.

Resulta que hay pocas formas de hacerlo. Primero, podríamos recorrer las claves directamente:  para clave en el diccionario Alternativamente, es posible que solo necesitemos recorrer los valores:  for value en dictionary.values ​​() Dicho esto, la mayoría de las personas probablemente necesiten poder hacer ambas cosas al mismo tiempo:  para clave, valor en dictionary.items () .

Si está interesado en obtener más información sobre estas soluciones, el resto de este artículo tomará un tiempo para ayudarlo. Por lo menos, me encantaría que completaras el desafío a continuación.

Descripción del problema

En el pasado,  hablábamos de escribir bucles en general . Por supuesto, cuando se trata de trabajar con estructuras de datos comunes como listas y tuplas en Python, recorrerlas es muy sencillo:

1
2
3
data = [1, 5, 4, 3]<font></font>
for num in data:<font></font>
  pass  # Do something!<font></font>

Sin embargo, una vez que empezamos a hablar de estructuras de datos más complicadas como los diccionarios, la iteración se vuelve un poco más complicada. Por ejemplo, aquí hay un diccionario que usaremos a lo largo de este artículo:

1
2
3
4
5
players = {<font></font>
  "Crosby": 87,<font></font>
  "Malkin": 71,<font></font>
  "Letang": 58<font></font>
}<font></font>

Si queremos recorrer esto, ¿en qué orden podemos esperar que esté? Y, ¿tiene sentido el concepto de ordenar? Asimismo, ¿cómo se ven los elementos durante la iteración?

Antes de sumergirnos, creo que es importante abordar un par de estas preguntas desde el principio. Primero, los diccionarios tienen un orden temporal, al menos desde Python 3.7, lo que significa que los elementos se ordenan según el orden en que se agregaron.

Dicho esto, la pregunta del elemento es un poco más complicada, por lo que tomaremos el resto de este artículo para responderla.

Soluciones

En este punto, sigamos adelante y comencemos a hablar sobre cómo iterar realmente sobre un diccionario. Resulta que hay tres formas principales de hacerlo, y todo depende de nuestras necesidades. Dicho esto, comenzaremos mirando las claves y los valores por separado y terminaremos con una forma de recorrer ambos al mismo tiempo.

Iterando sobre claves de diccionario

Si usáramos la misma estrategia en el diccionario que usamos en la lista anterior, podemos encontrarnos un poco confundidos ( como lo hace una persona en esta pregunta de StackOverflow ):

01
02
03
04
05
06
07
08
09
10
11
players = {<font></font>
  "Crosby": 87,<font></font>
  "Malkin": 71,<font></font>
  "Letang": 58<font></font>
}<font></font>
for player in players:<font></font>
  print(player)<font></font>
# Prints the following:<font></font>
# Crosby<font></font>
# Malkin<font></font>
# Letang<font></font>

Como podemos ver, la variable player parece almacenar cada clave. Para hacer uso de esta información, necesitaremos usar estas claves para acceder a nuestros valores:

01
02
03
04
05
06
07
08
09
10
11
players = {<font></font>
  "Crosby": 87,<font></font>
  "Malkin": 71,<font></font>
  "Letang": 58<font></font>
}<font></font>
for player in players:<font></font>
  print(f'{player}\'s number is {players[player]}')<font></font>
# Prints the following:<font></font>
# Crosby's number is 87<font></font>
# Malkin's number is 71<font></font>
# Letang's number is 58<font></font>

Observe cómo usamos la variable player para acceder a nuestro diccionario de jugadores. En cada pase, recogimos un nuevo jugador y recuperamos su número directamente.

Iterar los valores del diccionario

Si por alguna razón no necesitamos claves, Python nos da la opción de iterar sobre los valores en su lugar:

01
02
03
04
05
06
07
08
09
10
11
players = {<font></font>
  "Crosby": 87,<font></font>
  "Malkin": 71,<font></font>
  "Letang": 58<font></font>
}<font></font>
for number in players.values():<font></font>
  print(number)<font></font>
# Prints the following:<font></font>
# 87<font></font>
# 71<font></font>
# 58<font></font>

Aquí, hemos usado el método de los diccionarios de valores () para recuperar un objeto dict_values ​​iterable. De esa manera, podemos recorrer los valores y trabajar con ellos directamente.

Si por alguna razón, necesitamos recuperar una clave asociada con un valor, podemos hacerlo. De hecho,  tengo un artículo completo por separado sobre búsquedas inversas de diccionario . Dicho esto, probablemente se avecina una opción aún mejor.

Iterando sobre claves y valores de diccionario

Hasta este punto, hemos estado iterando sobre las claves y los valores por separado. Resulta que hay formas de iterar sobre ambos al mismo tiempo:

01
02
03
04
05
06
07
08
09
10
11
players = {<font></font>
  "Crosby": 87,<font></font>
  "Malkin": 71,<font></font>
  "Letang": 58<font></font>
}<font></font>
for player, number in players.items():<font></font>
  print(f'{player}\'s number is {number}')<font></font>
# Prints the following:<font></font>
# Crosby's number is 87<font></font>
# Malkin's number is 71<font></font>
# Letang's number is 58<font></font>
01
02
03
04
05
06
07
08
09
10
11
players = {<font></font>
  "Crosby": 87,<font></font>
  "Malkin": 71,<font></font>
  "Letang": 58<font></font>
}<font></font>
for player, number in players.iteritems():<font></font>
  print(f'{player}\'s number is {number}')<font></font>
# Prints the following:<font></font>
# Crosby's number is 87<font></font>
# Malkin's number is 71<font></font>
# Letang's number is 58<font></font>

Suponiendo que estamos usando la última versión de Python, podemos iterar sobre claves y valores al mismo tiempo usando el método items (). Esencialmente, este método empaqueta cada clave y valor como una tupla que se puede desempaquetar usando la sintaxis de desempaquetado iterable (también conocida como desestructuración para ustedes, amigos de JavaScript).

Si está interesado en obtener más información sobre el desembalaje iterable, he incluido  un ejemplo en un artículo anterior de esta serie . Del mismo modo, la función también apareció en  mi lista de las funciones más interesantes del lenguaje de programación .

En cualquier caso, sigamos adelante y comparemos estas tres opciones en términos de rendimiento.

Actuación

Para comparar estas soluciones, tendremos que idear un escenario coherente. Aquí, asumiremos que necesitaremos tanto la clave como el valor. Obviamente, esto le da la ventaja a la solución items (), por lo que la razón es que este es probablemente el escenario más común.

En cualquier caso, usaremos la biblioteca timeit que ejecuta fragmentos de código como cadenas. Si está interesado en obtener más información sobre este proceso de prueba, consulte  mi artículo sobre pruebas de rendimiento en Python . De lo contrario, aquí están las cadenas:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
dieciséis
17
18
19
20
setup = """<font></font>
players = {<font></font>
  "Crosby": 87,<font></font>
  "Malkin": 71,<font></font>
  "Letang": 58<font></font>
}<font></font>
"""<font></font>
keys_solution = """<font></font>
for player in players:<font></font>
  player_info = f\"{player}'s number is {players[player]}\"<font></font>
"""<font></font>
values_solution = """<font></font>
for number in players.values():<font></font>
  player = next(player for player in players.keys() if players[player] == number)<font></font>
  player_info = f\"{player}'s number is {players[player]}\"<font></font>
"""<font></font>
items_solution = """<font></font>
for player, number in players.items():<font></font>
  player_info = f\"{player}'s number is {number}\"<font></font>
"""<font></font>

Ahora que tenemos nuestras cadenas, podemos comenzar nuestras pruebas:

1
2
3
4
5
6
7
>>> import timeit<font></font>
>>> min(timeit.repeat(setup=setup, stmt=keys_solution))<font></font>
0.6103567999998631<font></font>
>>> min(timeit.repeat(setup=setup, stmt=values_solution))<font></font>
2.5487096000001657<font></font>
>>> min(timeit.repeat(setup=setup, stmt=items_solution))<font></font>
0.6782263000000057<font></font>

Claramente, esto es un poco sorprendente debido a la búsqueda adicional requerida para la solución de claves. Habría asumido que la solución items () habría ganado. Naturalmente, no pude evitar probar este problema con un conjunto de datos más grande, así que amplié nuestro diccionario de jugadores:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
dieciséis
17
setup = """<font></font>
players = {<font></font>
  "Crosby": 87,<font></font>
  "Malkin": 71,<font></font>
  "Letang": 58,<font></font>
  "Guentzel": 59,<font></font>
  "Aston-Reese": 46,<font></font>
  "Blueger": 53,<font></font>
  "Johnson": 3,<font></font>
  "Jarry": 35,<font></font>
  "Murray": 30,<font></font>
  "Marino": 6,<font></font>
  "Rust": 17,<font></font>
  "Sheary": 43,<font></font>
  "Zucker": 16<font></font>
}<font></font>
"""<font></font>

Ahora que tenemos aproximadamente 4 veces más jugadores, revisemos nuestros algoritmos:

1
2
3
4
>>> min(timeit.repeat(setup=setup, stmt=keys_solution))<font></font>
2.6091060999997353<font></font>
>>> min(timeit.repeat(setup=setup, stmt=items_solution))<font></font>
2.5544105999997555<font></font>

Esta vez no me molesté en probar la solución de valores porque, bueno, ya es bastante lento. Dicho esto, parece que la solución de elementos ya está comenzando a superar la solución de claves. Me pregunto cómo sería esta prueba con más datos. ¡No dudes en probarlo y avísame!

Como referencia, probé todo este código en Python 3.7.3 en IDLE usando Windows 10.

Desafío

Ahora que sabemos cómo iterar sobre un diccionario, me pregunto si podríamos llevar parte de este conocimiento al siguiente nivel. Por ejemplo, ¿y si tuviéramos la siguiente estructura de datos?

1
2
3
4
5
6
7
health_data = (<font></font>
  (<font></font>
    "05-01-2020", # Date<font></font>
    180.5# Weight<font></font>
    8043  # Steps<font></font>
  ) ...<font></font>
)<font></font>

En otras palabras, tenemos algunos datos de salud en forma de una tupla de tuplas. Cada tupla interna tiene tres elementos de datos: fecha, pesos y pasos. ¿Existe alguna forma de procesar eficazmente cada fila de datos utilizando lo que hemos aprendido hoy?

Como siempre, compartiré mi respuesta en Twitter usando  #RenegadePython :

¿Hay otras formas de hacer esto? ¿Por qué no compartir su propia solución con el mismo hashtag? Si lo veo, ¡lo compartiré!

Un pequeño resumen

Como siempre, aquí está la lista de soluciones:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
dieciséis
17
players = {<font></font>
  "Crosby": 87,<font></font>
  "Malkin": 71,<font></font>
  "Letang": 58<font></font>
}<font></font>
# Loops over just the keys<font></font>
for player in players:<font></font>
  pass<font></font>
# Loops over just the values<font></font>
for number in players.values():<font></font>
  pass<font></font>
# Loops over both keys and values (Python 3)<font></font>
for player, number in players.items():<font></font>
  pass<font></font>
# Loops over both keys and values (Python 2)<font></font>
for player, number in players.iteritems():<font></font>
  pass<font></font>

Publicar un comentario

0 Comentarios