I have a list of dict which each dict can have a list of dict nested in like:
mydictlist = [{'name':'foo'}, {'name':'bar','next-level':[{'name':'next-level-foo'}, {'name':'next-level-bar'}] } ]
I am trying to flatten some kind of attribute like name in list comprehension like this:
flattened = [ *['{}_{}'.format(iter['name'],next['name']) for next in iter] if 'next-level' in iter else '{}'.format(iter['name']) for iter in mydictlist]
to get something like :
['foo', 'bar_next-level-foo', 'bar_next-level-bar']
but this result in error!. I can do it with for and if without list comprehension (and have done that) but I want to know what is the correct syntax for doing that with list (or tuple unpacking) and list comprehension?
The closest one I can do is to provide a "fake" second level when necessary, and ignoring it afterwards:
mydictlist = [{'name':'foo'}, {'name':'bar','next-level':[{'name':'next-level-foo'}, {'name':'next-level-bar'}] } ]
flattened = [ '{}_{}'.format(item['name'],next['name']) if next['name'] else item['name'] for item in mydictlist for next in (item['next-level'] if 'next-level' in item else [{'name':None}]) ]
Output:
['foo', 'bar_next-level-foo', 'bar_next-level-bar']
There do not seem a way for conditionally loop in a list comprehension. So if there are two for
-s, they will both run, but the "subject" of the second loop can be generated conditionally (originally I did that with a lambda, but apparently a parenthesed expression is enough).
Your attempt had a bug, for next in iter
should have been for next in iter['next-level']
(also, iter()
is a built-in function, so I renamed the thing to item
).
And if you tried something less ambitious, you would have encountered an explicit error message: iterable unpacking cannot be used in comprehension.