invert dictionary with list &c
Des Small
des.small at bristol.ac.uk
Thu Nov 27 07:24:39 EST 2003
anton muhin <antonmuhin.REMOVE.ME.FOR.REAL.MAIL at rambler.ru> writes:
> 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
As another poster noted, this latter is broken.
> > 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
I was anxious to extract the common pattern, if possible, but these
are clean enough that it seems slightly perverse.
[...]
> 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)
This, however, has given me ideas. It was never concision I wanted
but rather redundancy elimination, and the pattern I wanted _can_ be
written:
def dict_cons(iter, func, default):
def process_element(d, (k, v)):
val = d.get(k, default)
d.update(dict([[k, func(v, val)]]))
return d
return reduce(process_element, iter, {})
Which is not to say that it should be, of course.
Whereupon, we can say:
def count(l):
def pair_pad(l): return [(e, ()) for e in l]
return dict_cons(pair_pad(l), lambda k,d: d+1, 0)
def invert(d):
def invertitems(l): for k,v in l: yield v,k
def addtolist(k, l): return l+[k]
return dict_cons(invertitems(d.iteritems()),
addtolist, [])
Perhaps I'm terminally unpythonic, but I quite like these.
> count = lambda l: reduce(
> lambda d, e: (d.update(dict([(e, d.get(e, 0) + 1)])), d)[1],
> l, {}
> )
>
> :)
If Python's lambda wasn't so broken I'd use it all the time, for sure.
Des
--
"[T]he structural trend in linguistics which took root with the
International Congresses of the twenties and early thirties [...] had
close and effective connections with phenomenology in its Husserlian
and Hegelian versions." -- Roman Jakobson
More information about the Python-list
mailing list