3

I have a dictionary like this:

migration_dict = {'30005': ['key42750','key43119', 'key44103', ['key333'],
['key444'], ['keyxx']], '30003': ['key43220', 'key42244','key42230',
['keyzz'], ['kehh']]}

How can I flatten the values of every key in order to have something like this:

migration_dict = {'30005': ['key42750','key43119', 'key44103', 'key333',
'key444', 'keyxx'], '30003': ['key43220', 'key42244','key42230',
'keyzz', 'kehh']}
MSeifert
  • 145,886
  • 38
  • 333
  • 352
e7lT2P
  • 1,635
  • 5
  • 31
  • 57

5 Answers5

9

You can write a recursive function to flatten the value lists and use it in a dictionary comprehension to build a new dictionary:

def flatten(lst):
   for x in lst:
      if isinstance(x, list):
         for y in flatten(x): # yield from flatten(...) in Python 3
            yield y           #
      else:
         yield x

migration_dict = {k: list(flatten(v)) for k, v in dct.items()}
print(migration_dict)
# {'30005': ['key42750', 'key43119', 'key44103', 'key333', 'key444', 'keyxx'], '30003': ['key43220', 'key42244', 'key42230', 'keyzz', 'kehh']}

It handles any nesting depth in the dict value lists.

Moses Koledoye
  • 77,341
  • 8
  • 133
  • 139
2
for key in migration_dict:
    for i in migration_dict[key]:
        if type(i) == list:
            migration_dict[key].remove(i)
            for element in i:
                migration_dict[key].append(element)

Now this loop should do it. Note however, that this works only if the inner list doesn't have more lists within it. If it does then you might have to make a recursive function that flattens it out for you.

morfindel
  • 132
  • 9
2

If you don't mind using an 3rd party extension, you could use iteration_utilities.deepflatten1 and a dict-comprehension:

>>> from iteration_utilities import deepflatten
>>> {key: list(deepflatten(value, ignore=str)) for key, value in migration_dict.items()}
{'30003': ['key43220', 'key42244', 'key42230', 'keyzz', 'kehh'],
 '30005': ['key42750', 'key43119', 'key44103', 'key333', 'key444', 'keyxx']}

This flattens all iterable items in your values (except strings).


1 Disclaimer: I'm the author of that library

MSeifert
  • 145,886
  • 38
  • 333
  • 352
0

Heres a oneliner:

Consider this dict, same structure:

m =  {'a': ['k1', 'k2', 'k3', ['k4'], ['k5'], ['k6']],
     'b': ['k1', 'k2', 'k3', ['k4'], ['k5'], ['k6']]}

import itertools

d = {k:list(itertools.chain.from_iterable(itertools.repeat(x,1) if isinstance(x, str) else x for x in v)) for k,v in m.iteritems()}

{'a': ['k1', 'k2', 'k3', 'k4', 'k5', 'k6'],
 'b': ['k1', 'k2', 'k3', 'k4', 'k5', 'k6']}

You could also use a 3rd party library more-iterools,

t = {k: list(more_itertools.collapse(v, base_type=str)) for k,v in m.iteritems()}

 {'a': ['k1', 'k2', 'k3', 'k4', 'k5', 'k6'],
 'b': ['k1', 'k2', 'k3', 'k4', 'k5', 'k6']}
gold_cy
  • 13,648
  • 3
  • 23
  • 45
0

If its important to have flat values in your dictionary, maybe you could create a function that gets rid of all the (multi-dimensional)lists before adding them to the dictionary?

def flatten_values(value):
      if type(value) == list:
           for i in value:
                return i

Hope this helps, couldnt make this into a comment, because i don't have enough rep ;)

Ya boy
  • 103
  • 1
  • 8