0

I want to write a function which removes a user id from a dictionary. This is for a H.W assignment and it is one of the function for a movie recommender program I have to write.

def remove_unknown_movies(user_ratings, movies):
 """Modify the user_ratings dictionary so that only movie ids that are in 
 the movies dictionary is remaining. Remove any users in user_ratings that 
 have no movies rated.
 >>> small_ratings = {1001: {68735: 5.0, 302156: 3.5, 10: 4.5}, 1002: {11: 3.0}}
 >>> remove_unknown_movies(small_ratings, MOVIE_DICT_SMALL)
 >>> len(small_ratings)
 1
 >>> small_ratings[1001]
 {68735: 5.0, 302156: 3.5}
 >>> 1002 in small_ratings
 False
 """
 for user_id in user_ratings.items():
 for movie_id in movies.items():
 if movie_id not in user_id:
 del user_ratings[user_id[0]]

Note that MOVIE_DICT_SMALL = {68735: ('Warcraft', ['Action', 'Adventure', 'Fantasy']), 293660: ('Deadpool', ['Action', 'Adventure', 'Comedy']), 302156: ('Criminal', ['Action']), 124057: ('Kids of the Round Table', [])}

Expected output (as per docstring example): len(small_ratings) = 1

Actual output:

builtins.KeyError: 1001

What am I doing wrong and how can I get the desired output?

Tajinder
2,3484 gold badges38 silver badges58 bronze badges
asked Aug 8, 2019 at 3:07

3 Answers 3

1

Code below is what you want. Remember, when you want to change dict during for loops, you should first convert it to list. Or you will get error:dictionary changed size during iteration

small_ratings = {1001: {68735: 5.0, 302156: 3.5, 10: 4.5}, 1002: {11: 3.0}}
MOVIE_DICT_SMALL = {
 68735: ('Warcraft', ['Action', 'Adventure', 'Fantasy']),
 293660: ('Deadpool', ['Action', 'Adventure', 'Comedy']),
 302156: ('Criminal', ['Action']),
 124057: ('Kids of the Round Table', [])
}
for uid, uscores in list(small_ratings.items()):
 for mid in list(uscores):
 if mid not in MOVIE_DICT_SMALL.keys():
 del small_ratings[uid][mid]
 if small_ratings[uid] == {}:
 del small_ratings[uid]
print(small_ratings)

output

{1001: {68735: 5.0, 302156: 3.5}}
answered Aug 8, 2019 at 6:12
Sign up to request clarification or add additional context in comments.

2 Comments

The thing is that I want the 1002 key to be removed aswell
@Stryk3r1337 It is easy, just delete keys whose value is empty dict.
0

The problem is on this line

del user_ratings[user_id[0]]

When you are on this line you delete an element in the dictionary. In the next iteration of the loop you try again to access this same element (i.e. user_ratings[user_id[0]]) but since this element is deleted you get a key error.

KeyError: 1001

This says that the key 1001 is not in your dictionary.

You can maintain a copy of this dict and delete items only from the copy and use the original to iterate over. Or, you can put in a try - catch block. But the simplest method would to check if the element is in dict before accessing it using if -else

answered Aug 8, 2019 at 3:53

Comments

0

So, I am a little unsure of exactly what you need to accomplish with this single function... It seems that you not only need to remove any irrelevant users from the small_ratings dict, but also make sure to remove any irrelevant movies from users ratings list.

Using dict.items() returns two values to unpack: keys, and values. You are only dealing with the returned keys. You can call just keys() or values(), but calling .items() is usually to deal with keys and values, like:

for k, v in d.items():
 key, value = k, v

Also, in Python 3, the default behavior when removing keys while iterating over a dictionary has changed -- you will get an error message if you remove the key while iterating.

So, you can do a dict.copy() of your dictionary value, and return the modified copy that you've deleted from, or you can do something like this example, where you create an empty list and append items marked for deletion to it, then iterate over your dictionary object and delete the keys with del.

#!/usr/bin/env python3
MOVIE_DICT_SMALL = {
 68735: ('Warcraft', ['Action', 'Adventure', 'Fantasy']),
 293660: ('Deadpool', ['Action', 'Adventure', 'Comedy']),
 302156: ('Criminal', ['Action']),
 124057: ('Kids of the Round Table', [])
}
small_ratings = {1001: {68735: 5.0, 302156: 3.5, 10: 4.5}, 1002: {11: 3.0}}
def remove_users(user_ratings, movies):
 delete = []
 for user_id in user_ratings:
 if not any(movie_id in movies.keys()
 for movie_id in user_ratings[user_id].keys()):
 delete.append(user_id)
 for user in delete:
 del user_ratings[user]
def remove_movies(user_ratings, movies):
 for user_id in user_ratings:
 delete = []
 for movie_id in user_ratings[user_id].keys():
 if movie_id not in movies.keys():
 delete.append(movie_id)
 for movie in delete:
 del user_ratings[user_id][movie]
remove_users(small_ratings, MOVIE_DICT_SMALL)
print(small_ratings) # {1001: {68735: 5.0, 302156: 3.5, 10: 4.5}}
remove_movies(small_ratings, MOVIE_DICT_SMALL)
print(small_ratings) # {1001: {68735: 5.0, 302156: 3.5}}
answered Aug 8, 2019 at 4:25

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.