Question

What is the pythonic way to reverse a defaultdict(list)?

I could iterating through the defaultdict and creating a new defaultdict. Is there any other way? Is this pythonic:

>>> from collections import defaultdict
>>> x = defaultdict(list)
>>> y = [[1,2,3,4],[3,4,5,6]]
>>> z= ['a','b']
>>> for i,j in zip(y,z):
...     x[j] = i
... 
>>> x
defaultdict(<type 'list'>, {'a': [1, 2, 3, 4], 'b': [3, 4, 5, 6]})
>>> x2 = defaultdict(list)
>>> for k,v in x.items():
...     for i in v:
...             x2[i].append(k)
... 
>>> x2
defaultdict(<type 'list'>, {1: ['a'], 2: ['a'], 3: ['a','b'], 4: ['a','b'], 5: ['b'], 6: ['b']})
Was it helpful?

Solution

I believe the best way is to simply loop as you did:

target = defaultdict(list)
for key, values in original.items():
    for value in values:
        target[value].append(key)

Alternatively you could avoid the inner for:

for key, values in original.items():
    target.update(zip(values, [key] * len(values)))

Or using itertools.repeat:

import itertools as it

for key, values in original.items():
    target.update(zip(values, it.repeat(key)))

However these last solutions only work for the simple case where values in different lists are distinct.


Remember that pythonic doesn't have any definite meaning. I'd consider python a solution that is:

  1. Readable
  2. Correctly use the language features
  3. Correctly use the built-ins/standard library
  4. Efficient

And the points are in order of importance. Efficience is last because it is most often implied by point 2 and 3.

OTHER TIPS

Is this more pythonic or just more cryptic?

map(lambda (i, k): x2[i].append(k), [(i, k) for i in v for k, v in x.items()])

Following variant is required for python 3, and is less clear:

map(lambda i_k: x2[i_k[0]].append(i_k[1]), [(i, k) for i in v for k, v in x.items()])

Writing this, I've concluded this is probably about the least pythonic way of doing it. But possibly educational; it was for me.

Edit: Don't do this.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top