¿Extraer un subconjunto de pares clave-valor del diccionario?

6 minutos de lectura

Avatar de usuario de Jayesh
Jayesh

Tengo un gran objeto de diccionario que tiene varios pares de valores clave (alrededor de 16), pero solo estoy interesado en 3 de ellos. ¿Cuál es la mejor manera (más corta/eficiente/más elegante) de dividir dicho diccionario en subconjuntos?

Lo mejor que sé es:

bigdict = {'a':1,'b':2,....,'z':26} 
subdict = {'l':bigdict['l'], 'm':bigdict['m'], 'n':bigdict['n']}

Estoy seguro de que hay una forma más elegante que esta.

Avatar de usuario de Mark Longair
marca longair

Tu podrías intentar:

dict((k, bigdict[k]) for k in ('l', 'm', 'n'))

… o en Pitón 3 Versiones de Python 2.7 o posteriores (gracias a Fábio Diniz por señalar que también funciona en 2.7):

{k: bigdict[k] for k in ('l', 'm', 'n')}

Actualización: como señala Håvard S, supongo que sabe que las claves estarán en el diccionario; vea su respuesta si no puede hacer esa suposición. Alternativamente, como timbo señala en los comentarios, si desea una clave que falta en bigdict mapear a Nonetu puedes hacer:

{k: bigdict.get(k, None) for k in ('l', 'm', 'n')}

Si está utilizando Python 3 y solamente quiere claves en el dictado nuevo que realmente existen en el original, puede usar el hecho para ver objetos implementar algunas operaciones establecidas:

{k: bigdict[k] for k in bigdict.keys() & {'l', 'm', 'n'}}

  • fallará si bigdict no contiene k

    – Håvard S

    18 de marzo de 2011 a las 13:29

  • {k: bigdict.get(k,None) for k in ('l', 'm', 'n')} se ocupará de la situación en la que falta una clave específica en el diccionario de origen configurando la clave en el nuevo dict en Ninguno

    – timbó

    21 de diciembre de 2013 a las 22:44


  • @MarkLongair Dependiendo del caso de uso {k: bigdict[k] for k in (‘l’,’m’,’n’) if k in bigdict} podría ser mejor, ya que solo almacena las claves que realmente tienen valores.

    – Brian Wylie

    07/03/2014 a las 22:20


  • bigdict.keys() & {'l', 'm', 'n'} ==> bigdict.viewkeys() & {'l', 'm', 'n'} para Python2.7

    – kxr

    25 de agosto de 2016 a las 15:58

  • ¿Qué pasa si mi dict ¿es demasiado grande?

    – Adamantish

    17 de marzo de 2021 a las 22:12

Avatar de usuario de Håvard S
Havard S

Un poco más corto, al menos:

wanted_keys = ['l', 'm', 'n'] # The keys you want
dict((k, bigdict[k]) for k in wanted_keys if k in bigdict)

  • +1 para el comportamiento alternativo de excluir una clave si no está en bigdict en lugar de establecerla en Ninguno.

    – dhj

    12/06/2014 a las 18:35

  • Alternativamente: dict((k,bigdict.get(k,defaultVal) for k in wanted_keys) si debe tener todas las llaves.

    – Thomas Andrews

    1 mayo 2018 a las 20:57

  • Esta respuesta se salva con una “t”.

    – sakura shinken

    29 de mayo de 2019 a las 7:42

  • También una variante un poco más corta (sintaxis) de su solución es cuando se usa {}es decir {k: bigdict[k] for k in wanted_keys if k in bigdict}

    – Arty

    4 de octubre de 2021 a las 3:42


Avatar de usuario de Sklavit
Sklavit

Un poco de comparación de velocidad para todos los métodos mencionados:

ACTUALIZADO el 2020.07.13 (gracias a @user3780389): SOLO para claves de bigdict.

 IPython 5.5.0 -- An enhanced Interactive Python.
Python 2.7.18 (default, Aug  8 2019, 00:00:00) 
[GCC 7.3.1 20180303 (Red Hat 7.3.1-5)] on linux2
import numpy.random as nprnd
  ...: keys = nprnd.randint(100000, size=10000)
  ...: bigdict = dict([(_, nprnd.rand()) for _ in range(100000)])
  ...: 
  ...: %timeit {key:bigdict[key] for key in keys}
  ...: %timeit dict((key, bigdict[key]) for key in keys)
  ...: %timeit dict(map(lambda k: (k, bigdict[k]), keys))
  ...: %timeit {key:bigdict[key] for key in set(keys) & set(bigdict.keys())}
  ...: %timeit dict(filter(lambda i:i[0] in keys, bigdict.items()))
  ...: %timeit {key:value for key, value in bigdict.items() if key in keys}
100 loops, best of 3: 2.36 ms per loop
100 loops, best of 3: 2.87 ms per loop
100 loops, best of 3: 3.65 ms per loop
100 loops, best of 3: 7.14 ms per loop
1 loop, best of 3: 577 ms per loop
1 loop, best of 3: 563 ms per loop

Como era de esperar: las comprensiones de diccionario son la mejor opción.

  • Las primeras 3 operaciones están haciendo algo diferente a las dos últimas y darán como resultado un error si key no existe en bigdict.

    – nada101

    19 de junio de 2020 a las 1:56

  • bonito. tal vez valga la pena agregar {key:bigdict[key] for key in bigdict.keys() & keys} de la solución aceptada que logra el filtro mientras que en realidad es más rápido (en mi máquina) que el primer método que enumera que no filtra. En realidad, {key:bigdict[key] for key in set(keys) & set(bigdict.keys())} parece ser aún más rápido para estos juegos de llaves tan grandes…

    – teichert

    8 julio 2020 a las 18:30

  • @telchert te estás perdiendo, que en la comparación de velocidad de entrega bigdict.keys() & keys no son conjuntos. Y con la conversión explícita a conjuntos, la solución aceptada no es tan rápida.

    – Sklavit

    18 oct 2021 a las 13:58

avatar de usuario de theheadofabroom
la cabeza de escoba

interesting_keys = ('l', 'm', 'n')
subdict = {x: bigdict[x] for x in interesting_keys if x in bigdict}

Esta respuesta usa una comprensión de diccionario similar a la respuesta seleccionada, pero no excepto en un elemento faltante.

versión de Python 2:

{k:v for k, v in bigDict.iteritems() if k in ('l', 'm', 'n')}

versión de Python 3:

{k:v for k, v in bigDict.items() if k in ('l', 'm', 'n')}

  • … pero si el dictado grande es ENORME, aún se repetirá por completo (esta es una operación O (n)), mientras que el inverso solo tomaría 3 elementos (cada uno una operación O (1)).

    – exterior reforzado

    5 oct 2015 a las 16:08

  • La pregunta es sobre un diccionario de solo 16 claves.

    – Maullar

    06/10/2015 a las 17:09

avatar de usuario de phimuemue
phimuemue

Quizás:

subdict=dict([(x,bigdict[x]) for x in ['l', 'm', 'n']])

Python 3 incluso admite lo siguiente:

subdict={a:bigdict[a] for a in ['l','m','n']}

Tenga en cuenta que puede verificar la existencia en el diccionario de la siguiente manera:

subdict=dict([(x,bigdict[x]) for x in ['l', 'm', 'n'] if x in bigdict])

resp. para pitón 3

subdict={a:bigdict[a] for a in ['l','m','n'] if a in bigdict}

  • … pero si el dictado grande es ENORME, aún se repetirá por completo (esta es una operación O (n)), mientras que el inverso solo tomaría 3 elementos (cada uno una operación O (1)).

    – exterior reforzado

    5 oct 2015 a las 16:08

  • La pregunta es sobre un diccionario de solo 16 claves.

    – Maullar

    06/10/2015 a las 17:09

Avatar de usuario de Kevin Grimm
kevin grimm

Un enfoque alternativo si desea conservar la mayoría de las claves mientras elimina algunas:

{k: bigdict[k] for k in bigdict.keys() if k not in ['l', 'm', 'n']}

  • Aún más corto: {k: v for k, v in bigdict.items() if k not in ['l', 'm', 'n']}

    – Pierresegonne

    11 oct 2021 a las 13:42

¿Ha sido útil esta solución?