anton muhin said:
Des said:
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