invert dictionary with list &c

anton muhin antonmuhin.REMOVE.ME.FOR.REAL.MAIL at rambler.ru
Wed Nov 26 13:05:12 EST 2003


Des Small wrote:

> Lately I have found myself using a pattern to make new dictionaries
> quite often, by which I mean twice:
> 
> def invert(d):
>     nd = {}
>     [nd.setdefault(val, []).append(key) for k, v in d]
>     return nd
> 
> def count(l):
>     d = {}
>     [d.setdefault(w, 0) += 1 for w in l]
>     return d
> 
> Is this the pythonic way to do such things?  Ideally I'd like to write
> them as one liners, but I can't see how.
> 
> Des

Most pythonic way IMHO would be:

def invert(d):
     nd = {}
     for k, v in d.iteritems():
         nd[v] = nd.get(k, []) + [k]
     return nd

def count(l):
     d = {}
     for e in l:
         d[e] = d.get(e, 0) + 1
     return d

Or to define dict with default values:

import copy

class defdict(dict):
     def __init__(self, default = None):
         self._default = default
         super(dict, self).__init__(self)

     def __getitem__(self, k):
         return self.get(k, copy.deepcopy(self._default)) # or setdefault

when

def invert(d):
     nd = defdict([])
     for k, v in d.iteritems():
         nd[v] += [k]
     return nd

def count(l):
     d = defdict(0)
     for e in l:
         d[e] += 1
     return d

However, if you insist on one-liners, I can suggest some ;):

def count(l):
   return reduce(
     lambda d, e: (d.update(dict([(e, d.get(e, 0) + 1)])), d)[1],
     l, {}
   )

def invert(d):
   return reduce(
     lambda d, (k, v): (d.update(dict([(v, d.get(v, []) + [k])])), d)[1],
     d.iteritems(), {}
   )

(given in several lines, but can be written in one)

or even

count = lambda l: reduce(
     lambda d, e: (d.update(dict([(e, d.get(e, 0) + 1)])), d)[1],
     l, {}
)

:)

regards,
anton.






More information about the Python-list mailing list