-
Notifications
You must be signed in to change notification settings - Fork 0
/
TomeRater.py
273 lines (229 loc) · 9.09 KB
/
TomeRater.py
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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
class User(object):
def __init__(self, name, email):
if ('@' in email) and (email.endswith('.org') or email.endswith('.edu') or email.endswith('.com')):
self.name = name
self.email = email
self.books = {}
else:
print('Unable to create new user. Incorrect email provided')
def get_email(self):
return self.email
def change_email(self, address):
self.email = address
print("The email address of {user} has been updated to {address}".format(user=self.name, address = self.email))
def __repr__(self):
return "User {user}, email: {address}, books read: {books}".format(user=self.name, address=self.email, books =str(len(self.books)))
def __eq__(self, other_user):
'''
two users are equal if they have the same name and email
'''
if (self.name == other_user.name) and (self.email == other_user.email):
return True
return False
def read_book(self, book, rating = None):
self.books[book] = rating
def get_average_rating(self):
sum_ratings = 0
for book_rating in self.books.values():
if book_rating != None:
sum_ratings += book_rating
average_rating = sum_ratings / len(self.books)
return average_rating
class Book(object):
def __init__(self, title, isbn, price):
'''
title - string
isbn - number
'''
self.title = title
self.isbn = isbn
self.price = price
self.ratings = []
def __repr__(self):
return "Book named {title} costs {price}".format(title=self.title, price = self.price)
def get_title(self):
return self.title
def get_isbn(self):
return self.isbn
def set_isbn(self, new_isbn):
self.isbn = new_isbn
print("ISBN for {book} updated to {isbn}".format(book = self.title, isbn = self.isbn))
def add_rating(self, rating):
'''
valid rating = 0 .. 4
'''
if (rating!= None):
if (rating >=0) and (rating <=4):
self.ratings.append(rating)
else:
print("Invalid Rating")
else:
print('Rating not provided')
def __eq__(self, other_book):
'''
books are equal if they have the same title and isbn
'''
if (self.title == other_book.title) and (self.isbn == other_book.isbn):
return True
return False
def get_average_rating(self):
sum_ratings = 0
for book_rating in self.ratings:
sum_ratings += book_rating
average_rating = sum_ratings / len(self.ratings)
return average_rating
def __hash__(self):
'''
hash method to allow Book objects to be dictionary keys
'''
return hash((self.title, self.isbn))
class Fiction(Book):
def __init__(self, title, author, isbn, price):
super().__init__(title, isbn, price)
self.author = author
def get_author(self):
return self.author
def __repr__(self):
return "{title} by {author} costs {price}".format(title = self.title, author = self.author, price = self.price)
class Non_Fiction(Book):
def __init__(self, title, subject, level, isbn, price):
super().__init__(title, isbn, price)
self.subject = subject
self.level = level
def get_subject(self):
return self.subject
def get_level(self):
return self.level
def __repr__(self):
return "{title}, a {level} manual on {subject} costs {price}".format(title = self.title, level = self.level, subject=self.subject, price = self.price)
class TomeRater(object):
def __init__(self):
self.users = {}
self.books = {}
def __repr__(self):
return "The object contains {users_num} users and {books_num} books read by them. For more details: use print_users() and print_catalog()".format(users_num = str(len(self.users)), books_num = str(len(self.books)))
def __eq__(self, other_tome_rater):
return (self.users == other_tome_rater.users) and (self.books == other_tome_rater.books)
def is_isbn_unique(self, isbn):
isbn_unique = True
for book in self.books:
if book.isbn == isbn:
isbn_unique = False
break
return isbn_unique
def create_book(self, title, isbn, price):
if self.is_isbn_unique(isbn):
new_book = Book(title, isbn, price)
return new_book
else:
print('Book with such ISBN already exists')
def create_novel(self, title, author, isbn, price):
if self.is_isbn_unique(isbn):
new_fiction = Fiction(title, author, isbn, price)
return new_fiction
else:
print('Book with such ISBN already exists')
def create_non_fiction(self, title, subject, level, isbn, price):
if self.is_isbn_unique(isbn):
new_non_fiction = Non_Fiction(title, subject, level, isbn, price)
return new_non_fiction
else:
print('Book with such ISBN already exists')
def add_book_to_user(self, book, email, rating = None):
if email not in self.users:
print("No user with email {email}".format(email=email))
else:
user = self.users[email]
user.read_book(book, rating)
book.add_rating(rating)
if book not in self.books:
self.books[book] = 1
else:
self.books[book] += 1
def add_user(self, name, email, user_books = None):
'''
create new user, add them and add books to their list (if provided)
'''
if email not in self.users:
new_user = User(name, email)
self.users[email] = new_user
if user_books != None:
for book in user_books:
self.add_book_to_user(book, email)
else:
print('User with email {email} already exists'.format(email = email))
def print_catalog(self):
'''
print all books: used as keys in the self.books
'''
for book in self.books:
print(book)
def print_users(self):
'''
print all users: values in self.users
'''
for user in self.users.values():
print(user)
def most_read_book(self):
'''
return the most read book in self.books: having the highest value in the self.books dict {book: how many times read}
'''
max_reads = float("-inf")
max_read_book = ''
for book, read_count in self.books.items():
if read_count > max_reads:
max_reads = read_count
max_read_book = book
return max_read_book
def get_n_most_read_books(self, n):
n_most_read_books = []
sorted_list_of_dict = sorted(self.books.items(), key = lambda kv: kv[1], reverse = True)
for i in range(min(n, len(sorted_list_of_dict))):
n_most_read_books.append(sorted_list_of_dict[i][0])
return n_most_read_books
def get_n_most_prolific_readers(self, n):
n_most_prolific_readers = []
book_prices = {}
for user in self.users:
book_prices[user] = len(self.users[user].books)
users_rating_sorted = sorted(book_prices.items(), key = lambda kv: kv[1], reverse=True)
for i in range(min(n, len(self.users))):
n_most_prolific_readers.append(self.users[users_rating_sorted[i][0]])
return n_most_prolific_readers
def highest_rated_book(self):
'''
return the book with highest average rating in self.books. Books are keys in self.books
'''
highest_rating = float("-inf")
highest_rated_book = ''
for book in self.books:
if book.get_average_rating() > highest_rating:
highest_rating = book.get_average_rating()
highest_rated_book = book
return highest_rated_book
def most_positive_user(self):
'''
return the user in self.users with the highest average rating
'''
max_average_rating = 0
most_positive_user = ''
for user in self.users.values():
if user.get_average_rating() > max_average_rating:
max_average_rating = user.get_average_rating()
most_positive_user = user
return most_positive_user
def get_worth_of_user(self, user_email):
total_cost = 0
for user in self.users.values():
for book in user.books:
total_cost += book.price
return total_cost
def get_n_most_expensive_books(self,n):
n_most_expensive_books = []
books_prices = {}
for book in self.books:
books_prices[book] = book.price
books_prices_sorted = sorted(books_prices.items(), key = lambda kv: kv[1], reverse=True)
for i in range(min(n, len(self.books))):
n_most_expensive_books.append(books_prices_sorted[i][0])
return n_most_expensive_books