简体   繁体   中英

List Comprehension of Lists Nested in Dictionaries

I have a dictionary where each value is a list, like so:

dictA = {1:['a','b','c'],2:['d','e']}

Unfortunately, I cannot change this structure to get around my problem

I want to gather all of the entries of the lists into one single list, as follows:

['a','b','c','d','e']

Additionally, I want to do this only once within an if-block. Since I only want to do it once, I do not want to store it to an intermediate variable, so naturally, a list comprehension is the way to go. But how? My first guess,

[dictA[key] for key in dictA.keys()]

yields,

[['a','b','c'],['d','e']]

which does not work because

'a' in  [['a','b','c'],['d','e']]

yields False . Everything else I've tried has used some sort of illegal syntax.

How might I perform such a comprehension?

Loop over the returned list too (looping directly over a dictionary gives you keys as well):

[value for key in dictA for value in dictA[key]]

or more directly using dictA.itervalues() :

[value for lst in dictA.itervalues() for value in lst]

List comprehensions let you nest loops; read the above loops as if they are nested in the same order:

for lst in dictA.itervalues():
    for value in lst:
        # append value to the output list

Or use itertools.chain.from_iterable() :

from itertools import chain

list(chain.from_iterable(dictA.itervalues()))

The latter takes a sequence of sequences and lets you loop over them as if they were one big list. dictA.itervalues() gives you a sequence of lists, and chain() puts them together for list() to iterate over and build one big list out of them.

If all you are doing is testing for membership among all the values, then what you really want is to a simple way to loop over all the values, and testing your value against each until you find a match. The any() function together with a suitable generator expression does just that:

any('a' in lst for lst in dictA.itervalues())

This will return True as soon as any value in dictA has 'a' listed, and stop looping over .itervalues() early.

If you're actually checking for membership (your a in... example), you could rewrite it as:

if any('a' in val for val in dictA.itervalues()):
    # do something

This saves having to flatten the list if that's not actually required.

In this particular case, you can just use a nested comprehension:

[value for key in dictA.keys() for value in dictA[key]]

But in general, if you've already figured out how to turn something into a nested list, you can flatten any nested iterable with chain.from_iterable :

itertools.chain.from_iterable(dictA[key] for key in dictA.keys())

This returns an iterator, not a list; if you need a list, just do it explicitly:

list(itertools.chain.from_iterable(dictA[key] for key in dictA.keys()))

As a side note, for key in dictA.keys() does the same thing as for key in dictA , except that in older versions of Python, it will waste time and memory making an extra list of the keys. As the documentation says, iter on a dict is the same as iterkeys .

So, in all of the versions above, it's better to just use in dictA instead.

In simple code just for understanding this might be helpful

ListA=[]
dictA = {1:['a','b','c'],2:['d','e']}
for keys in dictA:
    for values in dictA[keys]:
        ListA.append(values)

You can do some like ..

output_list = []

[ output_list.extend(x) for x in {1:['a','b','c'],2:['d','e']}.values()]

output_list will be ['a', 'b', 'c', 'd', 'e']

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM