Making a list comprehension for a dict in a list in a list

I need to create a list comprehension that fetches values ​​from a dict inside a list in a list, and my attempts so far have not worked. The object looks like this:

MyList=[[{'animal':'A','color':'blue'},{'animal':'B','color':'red'}],[{'animal':'C','color':'blue'},{'animal':'D','color':'Y'}]] 

      

I want to extract the values ​​for each item in the dict / list / to get two new lists:

Animals=[[A,B],[C,D]]
Colors=[[blue,red],[blue,Y]]

      

Any suggestions? You don't have to use a list comprehension; this is just my starting point. Thank!

+3


source to share


2 answers


Animals = [[d['animal'] for d in sub] for sub in MyList]
Colors = [[d['color'] for d in sub] for sub in MyList]

      

Gives the desired output:

[['A', 'B'], ['C', 'D']]
[['blue', 'red'], ['blue', 'Y']]  # No second 'red'.

      




What I have done here is take each sub-list, then each dictionary, and then access the correct key.

+5


source


In one assignment (with a single list comprehension and using map

and zip

):

Colors, Animals =  map(list, 
                       zip(*[map(list, 
                                 zip(*[(d['color'], d['animal']) for d in a])) 
                             for a in MyList]))

      

If you are ok with tuples you can avoid two calls to map => list

EDIT

Let's look at it in some detail, expanding the embedded understanding. Let's also assume that you MyList

have m

items for all n

objects (dictionaries).

[[d for d in sub] for sub in MyList]

      

This will go through every dictionary in the sublists. For each of them, we create a pair with a property color

in the first element and a property animal

in the second:

(d['color'], d['animal'])

      

As long as it takes time, proportional O(n)

- the elements will be processed exatly n

.

print [[(d['color'], d['animal']) for d in sub] for sub in MyList]

      



Now, for each of the substrings of the m

original list, we have one list of pairs that we need to unzip, i.e. convert it to two lists of single numbers. In Python, unzip is performed using a function zip

, passing a variable number of tuples as arguments (the arity of the first tuple determines the number of tuples received). For example, skipping 3 pairs, we get two lists of 3 elements each

>>> zip((1,2), (3,4), (5,6))  #Prints [(1, 3, 5), (2, 4, 6)]

      

To apply this to our case, we need to pass an array of pairs in zip

as a variable number of arguments: this is done using the splat operator, i.e. *

[zip(*[(d['color'], d['animal']) for d in sub]) for sub in MyList]

      

This operation requires going through each sublist once and in turn through each of the pairs that we created in the previous step. Thus, total running time O(n + n + m)

= O(n)

, with approximate operations 2*n + 2*m

.

So far, we have signatures m

, each of which contains two tuples (the first will collect all the colors for the sublists, the second - all the animals). To get two lists with m

tuples each, we unzip again

zip(*[zip(*[(d['color'], d['animal']) for d in sub]) for sub in MyList]

      

This will require additional steps m

- so the running time will remain O(n)

with approximately 2*n + 4*m

operations.

For simplicity's sake, we've left out the mapping of sets to lists in this analysis - that's fine if you're okay with tuples.

Tuples are immutable; however, they may not be. If you want lists of lists, you need to apply the function list

to each tuple: once for each of the adjustments m

(total elements 2*n

) and once for each of the 2 first level lists, i.e. animals and flowers (which have a total of m

items each). Assuming it list

takes time proportional to the length of the sequence to which it is applied, this extra step requires operations 2*n + 2*m

that are still there O(n)

.

+1


source







All Articles