Comprobar si una clave dada ya existe en un diccionario e incrementarla


Dado un diccionario, ¿cómo puedo averiguar si una clave dada en ese diccionario ya se ha establecido en un valor que no es Ninguno?

Es decir, quiero hacer esto:

my_dict = {}

if (my_dict[key] != None):
  my_dict[key] = 1
else:
  my_dict[key] += 1

Es decir, quiero incrementar el valor si ya hay uno allí, o establecerlo en 1 de lo contrario.

Author: Niels Bom, 2009-01-23

12 answers

Usted está buscando collections.defaultdict (disponible para Python 2.5+). Esto

from collections import defaultdict

my_dict = defaultdict(int)
my_dict[key] += 1

Hará lo que quieras.

Para Python dicts regulares, si no hay valor para una clave dada, no obtendrá None al acceder al dict a a KeyError se elevará. Así que si quieres usar un dict regular, en lugar de tu código usarías

if key in my_dict:
    my_dict[key] += 1
else:
    my_dict[key] = 1
 271
Author: dF.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-06-12 09:20:50

Prefiero hacer esto en una línea de código.

my_dict = {}

my_dict[some_key] = my_dict.get(some_key, 0) + 1

Los diccionarios tienen una función, get, que toma dos parámetros: la clave que desea y un valor predeterminado si no existe. Prefiero este método a defaultdict ya que solo desea manejar el caso donde la clave no existe en esta línea de código, no en todas partes.

 227
Author: Andrew Wilkinson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-03-30 17:43:25

Necesitas el modismo key in dict para eso.

if key in my_dict and not (my_dict[key] is None):
  # do something
else:
  # do something else

Sin embargo, probablemente deberías considerar usar defaultdict (como dF sugirió).

 47
Author: Eli Bendersky,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-01-23 15:38:55

Personalmente me gusta usar setdefault()

my_dict = {}

my_dict.setdefault(some_key, 0)
my_dict[some_key] += 1
 37
Author: kichik,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-03-30 18:39:12

Para responder a la pregunta " ¿cómo puedo averiguar si un índice dado en ese diccionario ya se ha establecido en un valor que no es ninguno", preferiría esto:

try:
  nonNone = my_dict[key] is not None
except KeyError:
  nonNone = False

Esto se ajusta al concepto ya invocado de EAFP (más fácil pedir perdón que permiso). También evita la búsqueda de claves duplicadas en el diccionario como lo haría en key in my_dict and my_dict[key] is not None lo que es interesante si la búsqueda es costosa.

Para el problema real que ha planteado, es decir, incrementar un int si existe, o configurarlo a un valor predeterminado de lo contrario, también recomiendo el

my_dict[key] = my_dict.get(key, default) + 1

Como en la respuesta de Andrew Wilkinson.

Hay una tercera solución si está almacenando objetos modificables en su diccionario. Un ejemplo común para esto es un multimap, donde almacena una lista de elementos para sus claves. En ese caso, puede usar:

my_dict.setdefault(key, []).append(item)

Si un valor para clave no existe en el diccionario, el método setdefault lo establecerá en el segundo parámetro de setdefault. Se se comporta como una[clave] estándar my_dict, devolviendo el valor de la clave (que puede ser el valor recién establecido).

 14
Author: nd.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-02-04 10:32:38

Como se puede ver en las muchas respuestas, hay varias soluciones. Una instancia de LBYL (mira antes de saltar) aún no ha sido mencionada, el método has_key ():

my_dict = {}

def add (key):
    if my_dict.has_key(key):
        my_dict[key] += 1
    else:
        my_dict[key] = 1

if __name__ == '__main__':
    add("foo")
    add("bar")
    add("foo")
    print my_dict
 11
Author: bortzmeyer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-01-23 16:17:20

De acuerdo con cgoldberg. Cómo lo hago es:

try:
    dict[key] += 1
except KeyError:
    dict[key] = 1

Así que, o bien hacerlo como se ha indicado anteriormente, o utilizar un dict predeterminado como otros han sugerido. No use declaraciones if. Eso no es Pitónico.

 10
Author: ryeguy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-01-23 15:09:59

Un poco tarde, pero esto debería funcionar.

my_dict = {}
my_dict[key] = my_dict[key] + 1 if key in my_dict else 1
 5
Author: Bob,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-12-30 11:00:52

La forma en que está tratando de hacerlo se llama LBYL (mire antes de saltar), ya que está verificando las condiciones antes de intentar incrementar su valor.

El otro enfoque se llama EAFP (más fácil pedir perdón que permiso). En ese caso, solo intentaría la operación (incrementar el valor). Si falla, captura la excepción y establece el valor en 1. Este es un poco más Python manera de hacerlo (OMI).

Http://mail.python.org/pipermail/python-list/2003-May/205182.html

 5
Author: Corey Goldberg,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-06-27 23:35:07

Esto no responde directamente a la pregunta, pero para mí, parece que es posible que desee la funcionalidad de las colecciones .Contador.

from collections import Counter

to_count = ["foo", "foo", "bar", "baz", "foo", "bar"]

count = Counter(to_count)

print(count)

print("acts just like the desired dictionary:")
print("bar occurs {} times".format(count["bar"]))

print("any item that does not occur in the list is set to 0:")
print("dog occurs {} times".format(count["dog"]))

print("can iterate over items from most frequent to least:")
for item, times in count.most_common():
    print("{} occurs {} times".format(item, times))

Esto resulta en la salida

Counter({'foo': 3, 'bar': 2, 'baz': 1})
acts just like the desired dictionary:
bar occurs 2 times
any item that does not occur in the list is set to 0:
dog occurs 0 times
can iterate over items from most frequent to least:
foo occurs 3 times
bar occurs 2 times
baz occurs 1 times
 4
Author: Izaak van Dongen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-08-19 22:47:28

Aquí hay una línea que se me ocurrió recientemente para resolver este problema. Se basa en el método del diccionario setdefault :

my_dict = {}
my_dict[key] = my_dict.setdefault(key, 0) + 1
 3
Author: Igor Gai,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-12-10 14:12:56

Lo estaba buscando, no lo encontré en la web, luego probé suerte con Try/Error y lo encontré

my_dict = {}

if my_dict.__contains__(some_key):
  my_dict[some_key] += 1
else:
  my_dict[some_key] = 1
 1
Author: AbhishekKr,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-03-30 17:46:24