-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathRecommender.cpp
135 lines (121 loc) · 5.4 KB
/
Recommender.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#include "Recommender.h"
#include "UserDatabase.h"
#include "MovieDatabase.h"
#include <string>
#include <vector>
#include <set>
#include <unordered_map>
#include <iostream>
#include "User.h"
using namespace std;
Recommender::Recommender(const UserDatabase& user_database, const MovieDatabase& movie_database)
{
m_udb = &user_database;
m_mb = &movie_database;
}
vector<MovieAndRank> Recommender::recommend_movies(const string& user_email, int movie_count) const
{
vector<MovieAndRank> movie_recs;
// get the user from the email address
User* uToRecommend = m_udb->get_user_from_email(user_email);
if(uToRecommend == nullptr)
{
return movie_recs;
}
// get the user watch history
vector<string> userWatchHistoryCopy = uToRecommend->get_watch_history();
// get the user watch history into a set so that it is faster to search through
set<string> userWatchHistory;
for(int i = 0; i < userWatchHistoryCopy.size(); i++)
{
userWatchHistory.insert(userWatchHistoryCopy[i]);
}
unordered_map<string, int> moviesWithScores;
set<string>::iterator s_it;
for(s_it = userWatchHistory.begin(); s_it != userWatchHistory.end(); s_it++)
{
Movie* processMovie = m_mb->get_movie_from_id(*s_it);
// make sure you aren't following nullptr
if(processMovie == nullptr)
{
return movie_recs;
}
// for each movie in the user's watch history, get a vector of the associated genres
vector<string> genres_in_movie = processMovie->get_genres();
for(int k = 0; k < genres_in_movie.size(); k++)
{
// for each genre, get a vector of assosiated movies
vector<Movie*> movies_with_genres = m_mb->get_movies_with_genre(genres_in_movie[k]);
for(int j = 0; j < movies_with_genres.size(); j++)
{
// if the movie isn't already watched by the user, map it into movieWithScores and add 1 to the score
set<string>::iterator already_watched = userWatchHistory.find(movies_with_genres[j]->get_id());
if(already_watched == userWatchHistory.end())
{
moviesWithScores[movies_with_genres[j]->get_id()] += 1;
}
}
}
// for each movie in the user's watch history, get a vector of the associated actors
vector<string> actors_in_movie = processMovie->get_actors();
for(int k = 0; k < actors_in_movie.size(); k++)
{
// for each actor, get a vector of assosiated movies
vector<Movie*> movies_with_actors = m_mb->get_movies_with_actor(actors_in_movie[k]);
for(int j = 0; j < movies_with_actors.size(); j++)
{
// if the movie isn't already watched by the user, map it into movieWithScores and add 30 to the score
set<string>::iterator already_watched = userWatchHistory.find(movies_with_actors[j]->get_id());
if(already_watched == userWatchHistory.end())
{
moviesWithScores[movies_with_actors[j]->get_id()] += 30;
}
}
}
// for each movie in the user's watch history, get a vector of the associated directors
vector<string> directors_in_movie = processMovie->get_directors();
for(int k = 0; k < directors_in_movie.size(); k++)
{
// for each director, get a vector of assosiated movies
vector<Movie*> movies_with_director = m_mb->get_movies_with_director(directors_in_movie[k]);
for(int j = 0; j < movies_with_director.size(); j++)
{
// if the movie isn't already watched by the user, map it into movieWithScores and add 20 to the score
set<string>::iterator already_watched = userWatchHistory.find(movies_with_director[j]->get_id());
if(already_watched == userWatchHistory.end())
{
moviesWithScores[movies_with_director[j]->get_id()] += 20;
}
}
}
}
map<Rec_Movie, pair<string, int>> m_recs;
unordered_map<string, int>::iterator umI = moviesWithScores.begin();
// traverse the unorderedmap that maps movieID's and scores
while(umI != moviesWithScores.end())
{
// get movie and score from the unorderedmap
Movie* movie = m_mb->get_movie_from_id(umI->first);
int score = umI->second;
Rec_Movie r_m(score, movie->get_rating(), movie->get_title());
// map each Rec_Movie to a map that maps rec_movies to a pair of movie id's and scores
// (can't map directly to MovieAndRank because it doesn't have a default constructor)
// when inserting r_m into this map, it will automatically be sorted via our custom operator<() function
m_recs[r_m] = {movie->get_id(), score};
umI++;
}
int count = 0;
map<Rec_Movie, pair<string, int>>::iterator findMatches;
// loop through the m_recs map, and append the first movie_count nums into the movie_recs vector
for(findMatches = m_recs.begin(); findMatches != m_recs.end(); findMatches++)
{
if(count == movie_count)
{
break;
}
MovieAndRank m_and_r(findMatches->second.first, findMatches->second.second);
movie_recs.push_back(m_and_r);
count++;
}
return movie_recs;
}