简体   繁体   中英

(Python 3) Sorting movies with dictionary and list

I am working on this project for school and I can't seem to get it perfect. I got the majority of it working but there's two things I am struggling with. After a few hours of googling and attempting various different workaround I have decided I need to ask for help.

def main():
    movieCollectionDict = {"Munich":[2005, "Steven Spielberg"],
                           "The Prestige": [2006, "Christopher Nolan"],
                           "The Departed": [2006, "Martin Scorsese"],
                           "Into the Wild": [2007, "Sean Penn"],
                           "The Dark Knight": [2008, "Christopher Nolan"],
                           "Mary and Max": [2009, "Adam Elliot"],
                           "The King\'s Speech": [2010, "Tom Hooper"],
                           "The Help": [2011, "Tate Taylor"],
                           "The Artist": [2011, "Michel Hazanavicius"],
                           "Argo": [2012, "Ben Affleck"],
                           "12 Years a Slave": [2013, "Steve McQueen"],
                           "Birdman": [2014, "Alejandro G. Inarritu"],
                           "Spotlight": [2015, "Tom McCarthy"],
                           "The BFG": [2016, "Steven Spielberg"]}
    promptForYear = True
    while promptForYear:
        yearChoice = int(input("Enter a year between 2005 and 2016:\n"))
        if yearChoice<2005 or yearChoice>2016:
            print("N/A")
        else:
            for key, value in movieCollectionDict.items():
                if value[0] == yearChoice:
                    print(key + ", " + str(value[1]) )
            promptForYear = False
    menu = "MENU" \
           "\nSort by:" \
           "\ny - Year" \
           "\nd - Director" \
           "\nt - Movie title" \
           "\nq - Quit\n"
    promptUser = True
    while promptUser:
        print("\n" + menu)
        userChoice = input("Choose an option:\n")
        if userChoice == "q":
            promptUser = False
        elif userChoice=="y":
            for key, value in sorted(movieCollectionDict.items(), key=lambda item: (item[1], item[0])):
                print (value[0],end=':\n')
                print("\t"+key + ", " + str(value[1])+"\n")
        elif userChoice == "d":
            for key, value in sorted(movieCollectionDict.items(), key=lambda key_value: key_value[1][1]):
                print(value[1],end=':\n')
                print("\t" + key + ", " + str(value[0])+"\n")
        elif userChoice == "t":
            for key, value in sorted(movieCollectionDict.items(), key=lambda item: (item[0], item[1])):
                print(key,end=':\n')
                print("\t" + str(value[1]) + ", " + str(value[0])+"\n")
        else:
            print("Invalid input")
main()

Basically I am having an issue, when I put in the year 2006. Instead of showing both movies from that year it prints them twice. Where did I go wrong with this?

I am also having an issue with an extra space at the end before the menu comes back up, it should have one space but it currently prints two blank lines.

This is the output:

2005:
    Munich, Steven Spielberg

2006:
    The Prestige, Christopher Nolan

2006:
    The Departed, Martin Scorsese

2007:
    Into the Wild, Sean Penn

2008:
    The Dark Knight, Christopher Nolan

I need both the movies from 2006 to be together and not separate.

Here is the example of the extra space:

2016:
The BFG, Steven Spielberg


MENU
Sort by:
y - Year
d - Director
t - Movie title
q - Quit

Choose an option:

Any help at all would be really appreciated!

Here is the solution. All the changes are in the if conditions of the while loop. To group the items based on year/director/title, a variable prev_value is used. Only when prev_value changes it is printed. This ensures grouping while printing sorted data. Also note the change where newlines are printed. They are now printed before the group header. That solves the double space issue.

def main():
    movieCollectionDict = {"Munich":[2005, "Steven Spielberg"],
                           "The Prestige": [2006, "Christopher Nolan"],
                           "The Departed": [2006, "Martin Scorsese"],
                           "Into the Wild": [2007, "Sean Penn"],
                           "The Dark Knight": [2008, "Christopher Nolan"],
                           "Mary and Max": [2009, "Adam Elliot"],
                           "The King\'s Speech": [2010, "Tom Hooper"],
                           "The Help": [2011, "Tate Taylor"],
                           "The Artist": [2011, "Michel Hazanavicius"],
                           "Argo": [2012, "Ben Affleck"],
                           "12 Years a Slave": [2013, "Steve McQueen"],
                           "Birdman": [2014, "Alejandro G. Inarritu"],
                           "Spotlight": [2015, "Tom McCarthy"],
                           "The BFG": [2016, "Steven Spielberg"]}
    promptForYear = True
    while promptForYear:
        yearChoice = int(input("Enter a year between 2005 and 2016:\n"))
        if yearChoice<2005 or yearChoice>2016:
            print("N/A")
        else:
            for key, value in movieCollectionDict.items():
                if value[0] == yearChoice:
                    print(key + ", " + str(value[1]) )
            promptForYear = False
    menu = "MENU" \
           "\nSort by:" \
           "\ny - Year" \
           "\nd - Director" \
           "\nt - Movie title" \
           "\nq - Quit\n"
    promptUser = True
    while promptUser:
        prev_val = ''
        print("\n" + menu)
        userChoice = input("Choose an option:\n")
        if userChoice == "q":
            promptUser = False
        elif userChoice=="y":
            for key, value in sorted(movieCollectionDict.items(), key=lambda item: (item[1], item[0])):
                if(prev_val!=value[0]):
                    print ("\n",value[0],end=':\n',sep='')
                    prev_val = value[0]
                print("\t"+key + ", " + str(value[1]))
        elif userChoice == "d":
            for key, value in sorted(movieCollectionDict.items(), key=lambda key_value: key_value[1][1]):
                if(prev_val!=value[1]):
                    print("\n",value[1],end=':\n',sep='')
                    prev_val = value[1]
                print("\t" + key + ", " + str(value[0]))
        elif userChoice == "t":
            for key, value in sorted(movieCollectionDict.items(), key=lambda item: (item[0], item[1])):
                if(prev_val!=key):
                    print("\n",key,end=':\n',sep='')
                    prev_val = key
                print("\t" + str(value[1]) + ", " + str(value[0]))
        else:
            print("Invalid input")
main()

Let's first understand the actual problem :

So suppose you have a list :

a=[(2006,1),(2007,4),(2008,9),(2006,5)]

And you want to convert this to a dict as the first element of the tuple as key and second element of the tuple. something like :

{2008: [9], 2006: [5], 2007: [4]}

But there is a catch you also want that those keys which have different values but keys are same like (2006,1) and (2006,5) keys are same but values are different. you want that those values append with only one key so expected output :

{2008: [9], 2006: [1, 5], 2007: [4]}

for this type of problem we do something like this:

first create a new dict then we follow this pattern:

if item[0] not in new_dict:
    new_dict[item[0]]=[item[1]]
else:
    new_dict[item[0]].append(item[1])

So we first check if key is in new dict and if it already then add the value of duplicate key to its value:

full code:

a=[(2006,1),(2007,4),(2008,9),(2006,5)]

new_dict={}

for item in a:
    if item[0] not in new_dict:
        new_dict[item[0]]=[item[1]]
    else:
        new_dict[item[0]].append(item[1])

print(new_dict)

Now let's back to your problem, you also want something like this so we can do :

elif userChoice=="y":
    new={}
    for key, value in sorted(movieCollectionDict.items()):
        for k in value:
            if value[0] not in new:
                new[value[0]]=[(key,value[1])]
            else:
                new[value[0]].append((key,value[1]))
    print({key: set(value) for key, value in new.items()})

So full code:

def main():
    movieCollectionDict = {"Munich":[2005, "Steven Spielberg"],
                           "The Prestige": [2006, "Christopher Nolan"],
                           "The Departed": [2006, "Martin Scorsese"],
                           "Into the Wild": [2007, "Sean Penn"],
                           "The Dark Knight": [2008, "Christopher Nolan"],
                           "Mary and Max": [2009, "Adam Elliot"],
                           "The King\'s Speech": [2010, "Tom Hooper"],
                           "The Help": [2011, "Tate Taylor"],
                           "The Artist": [2011, "Michel Hazanavicius"],
                           "Argo": [2012, "Ben Affleck"],
                           "12 Years a Slave": [2013, "Steve McQueen"],
                           "Birdman": [2014, "Alejandro G. Inarritu"],
                           "Spotlight": [2015, "Tom McCarthy"],
                           "The BFG": [2016, "Steven Spielberg"]}
    promptForYear = True
    while promptForYear:
        yearChoice = int(input("Enter a year between 2005 and 2016:\n"))
        if yearChoice<2005 or yearChoice>2016:
            print("N/A")
        else:
            for key, value in movieCollectionDict.items():
                if value[0] == yearChoice:
                    print(key + ", " + str(value[1]) )
            promptForYear = False
    menu = "MENU" \
           "\nSort by:" \
           "\ny - Year" \
           "\nd - Director" \
           "\nt - Movie title" \
           "\nq - Quit\n"
    promptUser = True
    while promptUser:
        print("\n" + menu)
        userChoice = input("Choose an option:\n")
        if userChoice == "q":
            promptUser = False
        elif userChoice=="y":
            new={}
            for key, value in sorted(movieCollectionDict.items()):
                for k in value:
                    if value[0] not in new:
                        new[value[0]]=[(key,value[1])]
                    else:
                        new[value[0]].append((key,value[1]))
            print({key: set(value) for key, value in new.items()})

        elif userChoice == "d":
            for key, value in sorted(movieCollectionDict.items(), key=lambda key_value: key_value[1][1]):
                print(value[1],end=':\n')
                print("\t" + key + ", " + str(value[0])+"\n")
        elif userChoice == "t":
            for key, value in sorted(movieCollectionDict.items(), key=lambda item: (item[0], item[1])):
                print(key,end=':\n')
                print("\t" + str(value[1]) + ", " + str(value[0])+"\n")
        else:
            print("Invalid input")
main()

PS : you can format the output as you want like key(year) in first line and values (movies name) in second line.

1:

Your problem is with the logic. This is the part where you'll be interested in.

elif userChoice=="y":
    prev_years = []
    for key, value in sorted(movieCollectionDict.items(), key=lambda item: (item[1], item[0])):
        if value[0] in prev_years:
            print("\t"+key + ", " + str(value[1])+"\n")
        else:
            print (value[0],end=':\n')
            print("\t"+key + ", " + str(value[1])+"\n")
        prev_years.append(value[0])

Notice I have added a list prev_years where I add years when I see them first.

For the first time i'll just check if 2005 is in my prev_years list. But starting it'll be empty. Hence the else part will execute!

else:
    print (value[0],end=':\n')
    print("\t"+key + ", " + str(value[1])+"\n")

Then i'll do this,

prev_years.append(value[0])

So now,

prev_years = [2005]

So when I see 2006 for the first time I do the same as above! and add it in my prev_years list

So now,

prev_years = [2005,2006]

Next comes the trick!

Take a look at my condition,

if value[0] in prev_years:
    print("\t"+key + ", " + str(value[1])+"\n")

So when the next year is already is in my prev_years list i just do the above. This gives you what you want!

2:

Take a look at this in interpreter,

>>> 
>>> print("hello");print("Vishnu")
hello
Vishnu
>>> print("hello"+"\n");print("Vishnu"+"\n")
hello

Vishnu

>>>

That's basically why extra space. print() by default puts a new line at the end. So remove all the backslash \\n 's and you've got what you wanted.

output:

Enter a year between 2005 and 2016:
2006
The Prestige, Christopher Nolan
The Departed, Martin Scorsese

MENU
Sort by:
y - Year
d - Director
t - Movie title
q - Quit

Choose an option:
y
2005:
    Munich, Steven Spielberg
2006:
    The Prestige, Christopher Nolan
    The Departed, Martin Scorsese
2007:
    Into the Wild, Sean Penn
2008:
    The Dark Knight, Christopher Nolan
2009:
    Mary and Max, Adam Elliot
2010:
    The King's Speech, Tom Hooper
2011:
    The Artist, Michel Hazanavicius
    The Help, Tate Taylor
2012:
    Argo, Ben Affleck
2013:
    12 Years a Slave, Steve McQueen
2014:
    Birdman, Alejandro G. Inarritu
2015:
    Spotlight, Tom McCarthy
2016:
    The BFG, Steven Spielberg

MENU
Sort by:
y - Year
d - Director
t - Movie title
q - Quit

Choose an option:

Improvement performed:

  1. Grouped the movies of same year when users sort the list by year.
  2. Grouped the movies of same director when users sort the list by director.
  3. Removed extra space before menu after first appearance.

I prefer using extra dictionary and clear variable name to make the code easier to read. Here is what I come up with. This is lengthy but seems logical to me. I assume you are learning programming. In this time, the more solutions you see of a particular problem, the more you will learn.

def main():
    movieCollectionDict = {"Munich":[2005, "Steven Spielberg"],
                           "The Prestige": [2006, "Christopher Nolan"],
                           "The Departed": [2006, "Martin Scorsese"],
                           "Into the Wild": [2007, "Sean Penn"],
                           "The Dark Knight": [2008, "Christopher Nolan"],
                           "Mary and Max": [2009, "Adam Elliot"],
                           "The King\'s Speech": [2010, "Tom Hooper"],
                           "The Help": [2011, "Tate Taylor"],
                           "The Artist": [2011, "Michel Hazanavicius"],
                           "Argo": [2012, "Ben Affleck"],
                           "12 Years a Slave": [2013, "Steve McQueen"],
                           "Birdman": [2014, "Alejandro G. Inarritu"],
                           "Spotlight": [2015, "Tom McCarthy"],
                           "The BFG": [2016, "Steven Spielberg"]}
    promptForYear = True
    while promptForYear:
        yearChoice = int(input("Enter a year between 2005 and 2016:\n"))
        if yearChoice<2005 or yearChoice>2016:
            print("N/A")   
        else:
            for key, value in movieCollectionDict.items():
                if value[0] == yearChoice:
                    print(key + ", " + str(value[1]) )
            promptForYear = False          
    menu = "MENU" \
           "\nSort by:" \
           "\ny - Year" \
           "\nd - Director" \
           "\nt - Movie title" \
           "\nq - Quit\n"
    promptUser = True
    first_time = True
    while promptUser:
        if first_time == True:
            print()
            first_time = False
        print(menu)
        userChoice = input("Choose an option:\n")
        if userChoice == "q":
            promptUser = False
        elif userChoice=="y":
            year_sorted = {}            
            for key, value in sorted(movieCollectionDict.items(), key=lambda item: (item[1], item[0])):
                year = value[0]
                title = key
                director = value[1]
                if year not in year_sorted:
                    year_sorted[year] = [[title, director]]
                else:
                    year_sorted[year].append([title, director])            
            for year in sorted(year_sorted):
                print (year,end=':\n')
                movies = year_sorted[year]
                for movie in sorted(movies, key = lambda x:x[0]):
                    print("\t"+movie[0] + ", " + movie[1])
                print()
        elif userChoice == "d":
            director_sorted = {}            
            for key, value in sorted(movieCollectionDict.items(), key=lambda item: (item[1][1])):
                year = value[0]
                title = key
                director = value[1]
                if director not in director_sorted:
                    director_sorted[director] = [[title, year]]
                else:
                    director_sorted[director].append([title, year])            
            for director in sorted(director_sorted):
                print (director,end=':\n')
                movies = director_sorted[director]
                for movie in sorted(movies, key = lambda x:x[0]):
                    print("\t"+movie[0] + ", " + str(movie[1]))            
                print()
        elif userChoice == "t":
            for key, value in sorted(movieCollectionDict.items(), key=lambda item: (item[0], item[1])):
                print(key,end=':\n')
                print("\t" + str(value[1]) + ", " + str(value[0])+"\n")
        else:
            print("Invalid input") 

main()

Output:

Enter a year between 2005 and 2016:
2006
The Prestige, Christopher Nolan
The Departed, Martin Scorsese

MENU
Sort by:
y - Year
d - Director
t - Movie title
q - Quit

Choose an option:
y
2005:
    Munich, Steven Spielberg

2006:
    The Departed, Martin Scorsese
    The Prestige, Christopher Nolan

2007:
    Into the Wild, Sean Penn

2008:
    The Dark Knight, Christopher Nolan

2009:
    Mary and Max, Adam Elliot

2010:
    The King's Speech, Tom Hooper

2011:
    The Artist, Michel Hazanavicius
    The Help, Tate Taylor

2012:
    Argo, Ben Affleck

2013:
    12 Years a Slave, Steve McQueen

2014:
    Birdman, Alejandro G. Inarritu

2015:
    Spotlight, Tom McCarthy

2016:
    The BFG, Steven Spielberg

MENU
Sort by:
y - Year
d - Director
t - Movie title
q - Quit

Choose an option:

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