Create list from nested list in dictionary

Question:

With below dictionary, I want to make a new single list with all directories:

nominated = {1931: ['Norman Taurog', 'Wesley Ruggles', 'Clarence Brown', 'Lewis Milestone', 'Josef Von Sternberg'],
             1932: ['Frank Borzage', 'King Vidor', 'Josef Von Sternberg'],
             1933: ['Frank Lloyd', 'Frank Capra', 'George Cukor']}

Desired output: 1 single list with all directors

all_directors = ['Norman Taurog', 'Wesley Ruggles', 'Clarence Brown', 'Lewis Milestone', 'Josef Von Sternberg','Frank Borzage', 'King Vidor', 'Josef Von Sternberg','Frank Lloyd', 'Frank Capra', 'George Cukor']

Attempt 1: list comprehension

all_directors = [[director for director in nominated_directors] for year, nominated_directors in nominated.items()]

print(all_directors)

Output attempt 1

[['Norman Taurog', 'Wesley Ruggles', 'Clarence Brown', 'Lewis Milestone', 'Josef Von Sternberg'], ['Frank Borzage', 'King Vidor', 'Josef Von Sternberg'], ['Frank Lloyd', 'Frank Capra', 'George Cukor']]

Attempt 1: using for loop

all_directors = []
for year, directors in nominated.items():
    for director in directors:
        all_directors.append(director)

print(all_directors)

Output attempt 2

['Norman Taurog', 'Wesley Ruggles', 'Clarence Brown', 'Lewis Milestone', 'Josef Von Sternberg', 'Frank Borzage', 'King Vidor', 'Josef Von Sternberg', 'Frank Lloyd', 'Frank Capra', 'George Cukor']

The output is correct with for loop but not list comprehension. Not sure what I missed, can you please help?

Asked By: Hana

||

Answers:

You can use sum to flatten the result.

all_directors = sum([[director for director in nominated_directors] for year,
                     nominated_directors in nominated.items()],
                    [])

You can also slim it down using map:

all_directors = sum(list(map(list, nominated.values())), [])

Or even further (thanks to Kelly Bundy in the comments) with:

sum(nominated.values(), [])
Answered By: Zac Anger
all_directors = [
    director for year, nominated_directors in nominated.items() 
    for director in nominated_directors
    ]

You can just remove the list notation from attempt 1 and re-order the for loops in list comprehension.

Answered By: Steven

you can use this nested loop in list comperhension to get all directories into single list

all_directors =[director for year, directors in nominated.items() for director in directors]
print(all_directors)

Answered By: ramasiva karri

You problem is a nested list comprehension case. Below is the solution.

all_directors = [director for nominated_directors in nominated.values() for director in nominated_directors]
Answered By: M2014

The problem you have here is the order you are iterating over items.

Your for loop correctly iterates over the major items (the sub lists of director names), then within that looping loops over the minor items (the actual names).

For some reason you’ve reversed this in your attempt at a list comprehension!

Sorting this out we have..

nominated = {1931: ['Norman Taurog', 'Wesley Ruggles', 'Clarence Brown', 'Lewis Milestone', 'Josef Von Sternberg'],
             1932: ['Frank Borzage', 'King Vidor', 'Josef Von Sternberg'],
             1933: ['Frank Lloyd', 'Frank Capra', 'George Cukor']}

all_directors  = [name for year,director_sublist in nominated.items() for name in director_sublist]

print(all_directors)


['Norman Taurog', 'Wesley Ruggles', 'Clarence Brown', 'Lewis Milestone', 'Josef Von Sternberg', 'Frank Borzage', 'King Vidor', 'Josef Von Sternberg', 'Frank Lloyd', 'Frank Capra', 'George Cukor']

Incidentally we don’t care about the dictionary keys (the years), so can dispense with them and just iterate over the dictionary values (the lists of director names)..

all_directors  = [name for director_sublist in nominated.values() for name in director_sublist]

Finally, why not make this a set rather than a list comprehension? Get rid of the duplicated names just by replacing […] with {…}

nominated = {1931: ['Norman Taurog', 'Wesley Ruggles', 'Clarence Brown', 'Lewis Milestone', 'Josef Von Sternberg'],
             1932: ['Frank Borzage', 'King Vidor', 'Josef Von Sternberg'],
             1933: ['Frank Lloyd', 'Frank Capra', 'George Cukor']}

all_directors  = {name for director_sublist in nominated.values() for name in director_sublist}

print(all_directors)

{'Frank Lloyd', 'Frank Capra', 'King Vidor', 'Josef Von Sternberg', 'Wesley Ruggles', 'Norman Taurog', 'Lewis Milestone', 'Frank Borzage', 'Clarence Brown', 'George Cukor'}
Answered By: Richard Plester

Use a generic function to flatten the dictionary’s values:

def flatten(items):
    """Yield items from any nested iterable"""
    for x in items:
        if isinstance(x, Iterable) and not isinstance(x, (str, bytes)):
            for sub_x in flatten(x):
                yield sub_x
            else:
                yield x

list(flatten(nominated.values()))

The function will handle greater depth nested lists than the 2d one in this scenario.

Answered By: gregory

There are tools in Python’s itertools library that could help you with this task such as chain.from_iterable

I saw in the comments that the ultimate goal for this data was to count how many nominations each director had gotten. This can be done with Python’s collections library and the Counter functionality.

As an example:

from collections import Counter
import itertools
from prettyprint


nominated = {1931: ['Norman Taurog', 'Wesley Ruggles', 'Clarence Brown', 'Lewis Milestone', 'Josef Von Sternberg'],
             1932: ['Frank Borzage', 'King Vidor', 'Josef Von Sternberg'],
             1933: ['Frank Lloyd', 'Frank Capra', 'George Cukor']}

director_count = Counter(itertools.chain.from_iterable(nominated.values()))
pprint(director_count)

Which gave the output:

Counter({'Josef Von Sternberg': 2,
         'Norman Taurog': 1,
         'Wesley Ruggles': 1,
         'Clarence Brown': 1,
         'Lewis Milestone': 1,
         'Frank Borzage': 1,
         'King Vidor': 1,
         'Frank Lloyd': 1,
         'Frank Capra': 1,
         'George Cukor': 1})
Answered By: ukBaz
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.