Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #7600 > unrolled thread

Dictionaries and incrementing keys

Started bySteve Crook <steve@mixmin.net>
First post2011-06-14 10:57 +0000
Last post2011-06-25 01:13 -0700
Articles 9 — 6 participants

Back to article view | Back to comp.lang.python


Contents

  Dictionaries and incrementing keys Steve Crook <steve@mixmin.net> - 2011-06-14 10:57 +0000
    Re: Dictionaries and incrementing keys Peter Otten <__peter__@web.de> - 2011-06-14 13:16 +0200
      Re: Dictionaries and incrementing keys AlienBaby <matt.j.warren@gmail.com> - 2011-06-14 05:37 -0700
        Re: Dictionaries and incrementing keys Steve Crook <steve@mixmin.net> - 2011-06-14 12:53 +0000
          Re: Dictionaries and incrementing keys Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2011-06-14 13:26 +0000
      Re: Dictionaries and incrementing keys Steve Crook <steve@mixmin.net> - 2011-06-14 12:57 +0000
    Re: Dictionaries and incrementing keys Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2011-06-14 13:24 +0000
    Re: Dictionaries and incrementing keys Asen Bozhilov <asen.bozhilov@gmail.com> - 2011-06-14 09:30 -0700
    Re: Dictionaries and incrementing keys Raymond Hettinger <python@rcn.com> - 2011-06-25 01:13 -0700

#7600 — Dictionaries and incrementing keys

FromSteve Crook <steve@mixmin.net>
Date2011-06-14 10:57 +0000
SubjectDictionaries and incrementing keys
Message-ID<slrnivefl8.47d.steve@news.mixmin.net>
Hi all,

I've always done key creation/incrementation using:

if key in dict:
    dict[key] += 1
else:
    dict[key] = 1

Today I spotted an alternative:

dict[key] = dict.get(key, 0) + 1

Whilst certainly more compact, I'd be interested in views on how
pythonesque this method is.

[toc] | [next] | [standalone]


#7601

FromPeter Otten <__peter__@web.de>
Date2011-06-14 13:16 +0200
Message-ID<it7fu4$rc5$1@solani.org>
In reply to#7600
Steve Crook wrote:

> I've always done key creation/incrementation using:
> 
> if key in dict:
>     dict[key] += 1
> else:
>     dict[key] = 1

Your way is usually faster than
 
> dict[key] = dict.get(key, 0) + 1
> 
> Whilst certainly more compact, I'd be interested in views on how
> pythonesque this method is.

You may also consider

http://docs.python.org/library/collections.html#collections.defaultdict
http://docs.python.org/library/collections.html#collections.Counter

[toc] | [prev] | [next] | [standalone]


#7603

FromAlienBaby <matt.j.warren@gmail.com>
Date2011-06-14 05:37 -0700
Message-ID<078c5e9a-8fad-4d4c-b081-f69d0f57593d@v11g2000prk.googlegroups.com>
In reply to#7601
On Jun 14, 12:16 pm, Peter Otten <__pete...@web.de> wrote:
> Steve Crook wrote:
> > I've always done key creation/incrementation using:
>
> > if key in dict:
> >     dict[key] += 1
> > else:
> >     dict[key] = 1
>
> Your way is usually faster than
>
> > dict[key] = dict.get(key, 0) + 1
>
> > Whilst certainly more compact, I'd be interested in views on how
> > pythonesque this method is.
>
> You may also consider
>
> http://docs.python.org/library/collections.html#collections.defaultdicthttp://docs.python.org/library/collections.html#collections.Counter



How do those methods compare to the one I normally use;

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

[toc] | [prev] | [next] | [standalone]


#7606

FromSteve Crook <steve@mixmin.net>
Date2011-06-14 12:53 +0000
Message-ID<slrnivemdn.47d.steve@news.mixmin.net>
In reply to#7603
On Tue, 14 Jun 2011 05:37:45 -0700 (PDT), AlienBaby wrote in
Message-Id: <078c5e9a-8fad-4d4c-b081-f69d0f57593d@v11g2000prk.googlegroups.com>:

> How do those methods compare to the one I normally use;
>
> try:
>  dict[key]+=1
> except:
>  dict[key]=1

This is a lot slower in percentage terms.  You should also qualify the
exception: except KeyError

[toc] | [prev] | [next] | [standalone]


#7609

FromSteven D'Aprano <steve+comp.lang.python@pearwood.info>
Date2011-06-14 13:26 +0000
Message-ID<4df76199$0$30002$c3e8da3$5496439d@news.astraweb.com>
In reply to#7606
On Tue, 14 Jun 2011 12:53:11 +0000, Steve Crook wrote:

> On Tue, 14 Jun 2011 05:37:45 -0700 (PDT), AlienBaby wrote in Message-Id:
> <078c5e9a-8fad-4d4c-b081-f69d0f57593d@v11g2000prk.googlegroups.com>:
> 
>> How do those methods compare to the one I normally use;
>>
>> try:
>>  dict[key]+=1
>> except:
>>  dict[key]=1
> 
> This is a lot slower in percentage terms.  You should also qualify the
> exception: except KeyError

Not necessarily. It depends on how often you have KeyError.

By my measurements, if the key is usually present, it is faster to use 
try...except. Only if the key is frequently missing does it become faster 
to test first.


-- 
Steven

[toc] | [prev] | [next] | [standalone]


#7607

FromSteve Crook <steve@mixmin.net>
Date2011-06-14 12:57 +0000
Message-ID<slrnivemlk.47d.steve@news.mixmin.net>
In reply to#7601
On Tue, 14 Jun 2011 13:16:47 +0200, Peter Otten wrote in
Message-Id: <it7fu4$rc5$1@solani.org>:

> Your way is usually faster than
>  
>> dict[key] = dict.get(key, 0) + 1

Thanks Peter, ran it through Timeit and you're right. It's probably also
easier to read the conditional version, even if it is longer.

> You may also consider
>
> http://docs.python.org/library/collections.html#collections.defaultdict
> http://docs.python.org/library/collections.html#collections.Counter

Useful functions, thanks again.

[toc] | [prev] | [next] | [standalone]


#7608

FromSteven D'Aprano <steve+comp.lang.python@pearwood.info>
Date2011-06-14 13:24 +0000
Message-ID<4df760f4$0$30002$c3e8da3$5496439d@news.astraweb.com>
In reply to#7600
On Tue, 14 Jun 2011 10:57:44 +0000, Steve Crook wrote:

> Hi all,
> 
> I've always done key creation/incrementation using:
> 
> if key in dict:
>     dict[key] += 1
> else:
>     dict[key] = 1
> 
> Today I spotted an alternative:
> 
> dict[key] = dict.get(key, 0) + 1
> 
> Whilst certainly more compact, I'd be interested in views on how
> pythonesque this method is.

Either version is perfectly fine. There's no reason to avoid either other 
than personal preference.

The "if key in dict" version does up to three item lookups (first to see 
if the key is in the dict, then to fetch the value, then to assign it), 
the version with dict.get only does two.

If the key has an expensive hash function, the version using dict.get 
will be much faster:

>>> key = ("abcdefgh"*10000, 5**30, frozenset(range(10000))) * 30
>>>
>>> from timeit import Timer
>>>
>>> t1 = Timer("""if key in d:
...     d[key] += 1
... else:
...     d[key] = 1
... """, "from __main__ import key; d = {key: 0}")
>>>
>>> t2 = Timer("d[key] = d.get(key, 0) + 1", 
... "from __main__ import key; d = {key: 0}")
>>>
>>> min(t1.repeat())
8.739075899124146
>>> min(t2.repeat())
6.425030946731567

but that will rarely be a problem in practice. For "normal" keys which 
are small strings or ints, the "if key in dict" version will usually be 
faster. Unless there are lots of missing keys, in which case the version 
using dict.get may be faster.

Either way, the difference is unlikely to be significant except for the 
tightest of tight loops. 


-- 
Steven

[toc] | [prev] | [next] | [standalone]


#7620

FromAsen Bozhilov <asen.bozhilov@gmail.com>
Date2011-06-14 09:30 -0700
Message-ID<8814af88-36b8-4a47-9bc2-dcb95857fe1c@r27g2000prr.googlegroups.com>
In reply to#7600
Steve Crook wrote:

> Whilst certainly more compact, I'd be interested in views on how
> pythonesque this method is.

Instead of calling function you could use:

d = {}

d[key] = (key in d and d[key]) + 1

Regards.

[toc] | [prev] | [next] | [standalone]


#8439

FromRaymond Hettinger <python@rcn.com>
Date2011-06-25 01:13 -0700
Message-ID<5623a36e-14c6-4c87-9af2-cc0b277d8d81@y30g2000yqb.googlegroups.com>
In reply to#7600
On Jun 14, 12:57 pm, Steve Crook <st...@mixmin.net> wrote:
> Today I spotted an alternative:
>
> dict[key] = dict.get(key, 0) + 1
>
> Whilst certainly more compact, I'd be interested in views on how
> pythonesque this method is.

It is very pythonesque in the it was the traditional one way to do it
(also one of the fastest ways).

Now we have collections.Counter which simplifies the code to:

   c = Counter()
   ...
   c[key] += 1

For existing keys, it is as fast as a regular dictionary (because it
is a dict subclass and it does not override or extend either
__getitem__ or __setitem__).  For new keys, it is a little slower
because it calls the __missing__ method which returns zero.

Raymond

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.python


csiph-web