invert dictionary with list &c

anton muhin antonmuhin.REMOVE.ME.FOR.REAL.MAIL at rambler.ru
Wed Nov 26 19:05:12 CET 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.

```