Hello, and welcome to today's lesson! Today, we are going to dive into the world of managing product reviews and applying data aggregation in practice. We will start with a relatively simple Starter Task to set up our base, and then gradually build up to a more complex solution involving data aggregation. Let's jump in!
For our starter task, we will lay the foundation by implementing basic operations for managing product reviews. The Review
struct encapsulates the details of a product review, consisting of the following fields:
std::string text
— The textual content of the review.int rating
— The rating score of the review, ranging from 1 to 5.bool flagged
— A boolean indicating whether the review is flagged as inappropriate.
These are the methods we will need to implement in a ReviewManager
class:
-
bool add_review(std::string product_id, std::string review_id, std::string review_text, int rating)
— adds a review to the product specified byproduct_id
. If a review withreview_id
already exists, it updates the existing review. Returnstrue
if the review was added or updated successfully,false
otherwise. For newly added items, theflagged
attribute is set tofalse
initially. -
std::optional<Review> get_review(std::string product_id, std::string review_id)
— returns the review details (text
,rating
, andflagged
fields) for the review specified byreview_id
under the givenproduct_id
. If the review or product does not exist, returnsstd::nullopt
. -
bool delete_review(std::string product_id, std::string review_id)
— deletes the review specified byreview_id
under the givenproduct_id
. Returnstrue
if the review was deleted,false
otherwise.
Let's look at the code that implements these functionalities:
C++1#include <iostream> 2#include <string> 3#include <unordered_map> 4#include <map> 5#include <optional> 6 7struct Review { 8 std::string text; 9 int rating; 10 bool flagged; 11}; 12 13class ReviewManager { 14private: 15 std::unordered_map<std::string, std::unordered_map<std::string, Review>> products; 16 17public: 18 bool add_review(const std::string& product_id, const std::string& review_id, const std::string& review_text, int rating) { 19 if (rating < 1 || rating > 5) { 20 return false; // Invalid rating 21 } 22 products[product_id][review_id] = {review_text, rating, false}; 23 return true; 24 } 25 26 std::optional<Review> get_review(const std::string& product_id, const std::string& review_id) { 27 if (products.count(product_id) && products[product_id].count(review_id)) { 28 return products[product_id][review_id]; 29 } 30 return std::nullopt; 31 } 32 33 bool delete_review(const std::string& product_id, const std::string& review_id) { 34 if (products.count(product_id) && products[product_id].count(review_id)) { 35 products[product_id].erase(review_id); 36 if (products[product_id].empty()) { 37 products.erase(product_id); // Remove product if no reviews left 38 } 39 return true; 40 } 41 return false; 42 } 43}; 44 45int main() { 46 ReviewManager review_manager; 47 48 // Adding some reviews 49 review_manager.add_review("p1", "r1", "Great product!", 5); 50 review_manager.add_review("p1", "r2", "Not bad", 3); 51 52 // Testing get_review method 53 auto review_r1 = review_manager.get_review("p1", "r1"); 54 if (review_r1) { 55 std::cout << "Review r1 for p1: {"; 56 std::cout << "text: " << review_r1->text << ", "; 57 std::cout << "rating: " << review_r1->rating << ", "; 58 std::cout << "flagged: " << review_r1->flagged << "}\n"; 59 } else { 60 std::cout << "Review r1 for p1 not found\n"; 61 } 62 63 auto review_r3 = review_manager.get_review("p1", "r3"); 64 if (review_r3) { 65 std::cout << "Review r3 for p1 found\n"; 66 } else { 67 std::cout << "Review r3 for p1 not found\n"; 68 } 69 70 // Testing delete_review method 71 if (review_manager.delete_review("p1", "r2")) { 72 std::cout << "Review r2 for p1 deleted successfully\n"; 73 } else { 74 std::cout << "Failed to delete review r2 for p1\n"; 75 } 76 77 auto review_r2 = review_manager.get_review("p1", "r2"); 78 if (review_r2) { 79 std::cout << "Review r2 for p1 found\n"; 80 } else { 81 std::cout << "Review r2 for p1 not found\n"; 82 } 83 84 return 0; 85}
This code establishes the foundational methods needed for managing product reviews within a ReviewManager
class. The add_review
method allows for adding a new review or updating an existing one, ensuring each review contains valid rating values between 1 and 5. The get_review
method retrieves the review details for a specific product, including the review text and rating, returning std::nullopt
if the product or review doesn't exist. The delete_review
method facilitates the removal of a specific review, and if no reviews are left for a product, the product itself is removed from the product list. Together, these methods form the basic operations required to manage a collection of product reviews efficiently.
Now, let's extend this with new features.
With our basic review management system in place, we will now introduce new methods to handle more complex operations, such as flagging inappropriate reviews and aggregating review data for a specific product.
Here are the new methods we will add:
-
bool flag_review(const std::string& product_id, const std::string& review_id)
— This method flags a specific review as inappropriate for a given product. Returnstrue
if the review was successfully flagged,false
otherwise. -
std::optional<AggregatedData> aggregate_reviews(const std::string& product_id)
— This method aggregates review data for a given product, providing statistics such as the total number of reviews, the number of flagged reviews, average rating, and review texts excluding flagged ones. If the product does not have any reviews or does not exist, returnsstd::nullopt
.
First, let's add functionality to flag a review:
C++1#include <iostream> 2#include <string> 3#include <unordered_map> 4#include <map> 5#include <optional> 6 7struct Review { 8 std::string text; 9 int rating; 10 bool flagged; 11}; 12 13class ReviewManager { 14private: 15 std::unordered_map<std::string, std::unordered_map<std::string, Review>> products; 16 17public: 18 bool add_review(const std::string& product_id, const std::string& review_id, const std::string& review_text, int rating) { 19 if (rating < 1 || rating > 5) { 20 return false; // Invalid rating 21 } 22 products[product_id][review_id] = {review_text, rating, false}; 23 return true; 24 } 25 26 std::optional<Review> get_review(const std::string& product_id, const std::string& review_id) { 27 if (products.count(product_id) && products[product_id].count(review_id)) { 28 return products[product_id][review_id]; 29 } 30 return std::nullopt; 31 } 32 33 bool delete_review(const std::string& product_id, const std::string& review_id) { 34 if (products.count(product_id) && products[product_id].count(review_id)) { 35 products[product_id].erase(review_id); 36 if (products[product_id].empty()) { 37 products.erase(product_id); // Remove product if no reviews left 38 } 39 return true; 40 } 41 return false; 42 } 43 44 bool flag_review(const std::string& product_id, const std::string& review_id) { 45 if (products.count(product_id) && products[product_id].count(review_id)) { 46 products[product_id][review_id].flagged = true; 47 return true; 48 } 49 return false; 50 } 51}; 52 53int main() { 54 ReviewManager review_manager; 55 56 // Adding some reviews 57 review_manager.add_review("p1", "r1", "Great product!", 5); 58 review_manager.add_review("p1", "r2", "Not bad", 3); 59 review_manager.add_review("p1", "r3", "Terrible", 1); 60 61 // Flagging a review 62 review_manager.flag_review("p1", "r3"); 63 64 // Testing flag_review method 65 auto review_r3 = review_manager.get_review("p1", "r3"); 66 if (review_r3) { 67 std::cout << "Review r3 for p1: {"; 68 std::cout << "text: " << review_r3->text << ", "; 69 std::cout << "rating: " << review_r3->rating << ", "; 70 std::cout << "flagged: " << review_r3->flagged << "}\n"; 71 } else { 72 std::cout << "Review r3 for p1 not found\n"; 73 } 74 75 return 0; 76}
In this step, we are adding the flag_review
method to our ReviewManager
class. This method enables users to mark a specific review as inappropriate. It checks whether the product and review exist in the dataset, and if they do, it sets the flagged
attribute of the review to true
. This flagging mechanism is crucial for maintaining the quality and appropriateness of the reviews in the system.
Next, we will implement the method to aggregate reviews:
C++1#include <iostream> 2#include <string> 3#include <unordered_map> 4#include <map> 5#include <optional> 6#include <vector> 7 8struct Review { 9 std::string text; 10 int rating; 11 bool flagged; 12}; 13 14struct AggregatedData { 15 int total_reviews; 16 int flagged_reviews; 17 double average_rating; 18 std::vector<std::string> review_texts; 19}; 20 21class ReviewManager { 22private: 23 std::unordered_map<std::string, std::unordered_map<std::string, Review>> products; 24 25public: 26 bool add_review(const std::string& product_id, const std::string& review_id, const std::string& review_text, int rating) { 27 if (rating < 1 || rating > 5) { 28 return false; // Invalid rating 29 } 30 products[product_id][review_id] = {review_text, rating, false}; 31 return true; 32 } 33 34 std::optional<Review> get_review(const std::string& product_id, const std::string& review_id) { 35 if (products.count(product_id) && products[product_id].count(review_id)) { 36 return products[product_id][review_id]; 37 } 38 return std::nullopt; 39 } 40 41 bool delete_review(const std::string& product_id, const std::string& review_id) { 42 if (products.count(product_id) && products[product_id].count(review_id)) { 43 products[product_id].erase(review_id); 44 if (products[product_id].empty()) { 45 products.erase(product_id); // Remove product if no reviews left 46 } 47 return true; 48 } 49 return false; 50 } 51 52 bool flag_review(const std::string& product_id, const std::string& review_id) { 53 if (products.count(product_id) && products[product_id].count(review_id)) { 54 products[product_id][review_id].flagged = true; 55 return true; 56 } 57 return false; 58 } 59 60 std::optional<AggregatedData> aggregate_reviews(const std::string& product_id) { 61 if (products.find(product_id) == products.end() || products[product_id].empty()) { 62 return std::nullopt; // No reviews or product doesn't exist 63 } 64 65 int total_reviews = products[product_id].size(); 66 int flagged_reviews = 0; 67 int total_rating = 0; 68 std::vector<std::string> review_texts; 69 70 for (const auto& [review_id, review] : products[product_id]) { 71 if (review.flagged) { 72 flagged_reviews++; 73 } else { 74 total_rating += review.rating; 75 review_texts.push_back(review.text); 76 } 77 } 78 79 double average_rating = (total_reviews == flagged_reviews) ? 0.0 : static_cast<double>(total_rating) / (total_reviews - flagged_reviews); 80 return AggregatedData{total_reviews, flagged_reviews, average_rating, review_texts}; 81 } 82}; 83 84int main() { 85 ReviewManager review_manager; 86 87 // Adding some reviews 88 review_manager.add_review("p1", "r1", "Great product!", 5); 89 review_manager.add_review("p1", "r2", "Not bad", 3); 90 review_manager.add_review("p1", "r3", "Terrible", 1); 91 92 // Flagging a review 93 review_manager.flag_review("p1", "r3"); 94 95 // Testing the aggregation method 96 auto aggregated_data = review_manager.aggregate_reviews("p1"); 97 if (aggregated_data) { 98 std::cout << "Aggregated data for p1: {\n"; 99 std::cout << "total_reviews: " << aggregated_data->total_reviews << ",\n"; 100 std::cout << "flagged_reviews: " << aggregated_data->flagged_reviews << ",\n"; 101 std::cout << "average_rating: " << aggregated_data->average_rating << ",\n"; 102 std::cout << "review_texts: ["; 103 for (const auto& text : aggregated_data->review_texts) { 104 std::cout << "\"" << text << "\", "; 105 } 106 std::cout << "]\n}"; 107 } else { 108 std::cout << "No aggregated data for p1\n"; 109 } 110 111 return 0; 112}
In this step, the aggregate_reviews
method is added to the ReviewManager
class, along with the definition of an AggregatedData
custom struct. The method aggregates review data for a given product by calculating various statistics, such as the total number of reviews, the number of flagged reviews, the average rating excluding flagged reviews, and a list of review texts that are not flagged. The method first ensures the product exists and contains reviews. It then iterates through the reviews to collect the necessary data, considering only non-flagged reviews for the average rating and review texts. If all reviews are flagged, the average rating defaults to zero. This aggregation provides a comprehensive overview of a product’s review status, useful for both users and administrators.
Great job! Today, you have learned how to manage product reviews and apply data aggregation in practice. We started with basic operations for adding, retrieving, and deleting reviews. Then, we extended our functionality to include flagging reviews and aggregating review data. This gradual build-up demonstrates how to enhance features incrementally and handle more complex data aggregation tasks.
Feel free to practice solving similar challenges to strengthen your skills further. Keep coding, and see you in the next lesson!