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. These are the methods we will need to implement:
-
addReview(string productId, string reviewId, string reviewText, int rating)
— adds a review to the product specified byproductId
. If a review withreviewId
already exists, it updates the existing review. The review contains aflagged
field which indicates whether the review is marked as inappropriate (by default, this field is set tofalse
). Returnstrue
if the review was added or updated successfully,false
otherwise. -
getReview(string productId, string reviewId)
— returns the review details (reviewText
,rating
, andflagged
fields) for the review specified byreviewId
under the givenproductId
. If the review or product does not exist, returnsnull
. -
deleteReview(string productId, string reviewId)
— deletes the review specified byreviewId
under the givenproductId
. Returnstrue
if the review was deleted,false
, otherwise.
Let's look at the code that implements these functionalities:
C#1using System; 2using System.Collections.Generic; 3 4public class ReviewManager 5{ 6 private Dictionary<string, Dictionary<string, Review>> products = new Dictionary<string, Dictionary<string, Review>>(); 7 8 public bool addReview(string productId, string reviewId, string reviewText, int rating) 9 { 10 if (rating < 1 || rating > 5) return false; // Invalid rating 11 12 if (!products.ContainsKey(productId)) 13 { 14 products[productId] = new Dictionary<string, Review>(); 15 } 16 17 products[productId][reviewId] = new Review { Text = reviewText, Rating = rating, Flagged = false }; 18 return true; 19 } 20 21 public Review getReview(string productId, string reviewId) 22 { 23 if (products.ContainsKey(productId) && products[productId].ContainsKey(reviewId)) 24 { 25 return products[productId][reviewId]; 26 } 27 return null; 28 } 29 30 public bool deleteReview(string productId, string reviewId) 31 { 32 if (products.ContainsKey(productId) && products[productId].ContainsKey(reviewId)) 33 { 34 products[productId].Remove(reviewId); 35 if (products[productId].Count == 0) products.Remove(productId); 36 return true; 37 } 38 return false; 39 } 40} 41 42public class Review 43{ 44 public string Text { get; set; } 45 public int Rating { get; set; } 46 public bool Flagged { get; set; } 47} 48 49public class Program 50{ 51 public static void Main() 52 { 53 ReviewManager reviewManager = new ReviewManager(); 54 55 // Adding some reviews 56 reviewManager.addReview("p1", "r1", "Great product!", 5); 57 reviewManager.addReview("p1", "r2", "Not bad", 3); 58 59 // Testing getReview method 60 var review1 = reviewManager.getReview("p1", "r1"); 61 if (review1 != null) Console.WriteLine($"Review1: {review1.Text}, Rating: {review1.Rating}, Flagged: {review1.Flagged}"); 62 else Console.WriteLine("Review not found"); 63 64 var review2 = reviewManager.getReview("p1", "r3"); 65 if (review2 != null) Console.WriteLine($"Review2: {review2.Text}, Rating: {review2.Rating}, Flagged: {review2.Flagged}"); 66 else Console.WriteLine("Review not found"); 67 68 // Testing deleteReview method 69 Console.WriteLine($"Delete review r2: {reviewManager.deleteReview("p1", "r2")}"); 70 var review3 = reviewManager.getReview("p1", "r2"); 71 if (review3 != null) Console.WriteLine($"Review3: {review3.Text}, Rating: {review3.Rating}, Flagged: {review3.Flagged}"); 72 else Console.WriteLine("Review not found"); 73 } 74}
This code establishes the foundational methods needed for managing product reviews within a ReviewManager
class. The addReview
method allows for adding a new review or updating an existing one, ensuring each review contains valid rating values between 1 and 5. The getReview
method retrieves the review details for a specific product, including the review text and rating, returning null
if the product or review doesn't exist. The deleteReview
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:
-
flagReview(string productId, string reviewId)
— this method flags a specific review as inappropriate for a given product. Returnstrue
if the review was successfully flagged,false
otherwise. -
aggregateReviews(string productId)
— this method aggregates review data for a given product, providing statistics such as the total number of reviews, the number of flagged reviews, the average rating, and review texts excluding flagged ones. If the product does not have any reviews or does not exist, returnsnull
.
First, let's add functionality to flag a review:
C#1using System; 2using System.Collections.Generic; 3 4public class ReviewManager 5{ 6 private Dictionary<string, Dictionary<string, Review>> products = new Dictionary<string, Dictionary<string, Review>>(); 7 8 // Existing methods... 9 10 public bool flagReview(string productId, string reviewId) 11 { 12 if (products.ContainsKey(productId) && products[productId].ContainsKey(reviewId)) 13 { 14 products[productId][reviewId].Flagged = true; 15 return true; 16 } 17 return false; 18 } 19} 20 21public class Review 22{ 23 public string Text { get; set; } 24 public int Rating { get; set; } 25 public bool Flagged { get; set; } 26} 27 28public class Program 29{ 30 public static void Main() 31 { 32 ReviewManager reviewManager = new ReviewManager(); 33 34 // Adding some reviews 35 reviewManager.addReview("p1", "r1", "Great product!", 5); 36 reviewManager.addReview("p1", "r2", "Not bad", 3); 37 reviewManager.addReview("p1", "r3", "Terrible", 1); 38 39 // Flagging a review 40 reviewManager.flagReview("p1", "r3"); 41 42 // Testing flagReview method 43 var review = reviewManager.getReview("p1", "r3"); 44 if (review != null) 45 { 46 Console.WriteLine($"Review: {review.Text}, Rating: {review.Rating}, Flagged: {review.Flagged}"); 47 } 48 } 49}
In this step, we are adding the flagReview
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#1using System; 2using System.Collections.Generic; 3using System.Linq; 4 5public class ReviewManager 6{ 7 private Dictionary<string, Dictionary<string, Review>> products = new Dictionary<string, Dictionary<string, Review>>(); 8 9 // Existing methods... 10 11 public ReviewAggregate aggregateReviews(string productId) 12 { 13 if (!products.ContainsKey(productId) || products[productId].Count == 0) 14 { 15 return null; // No reviews or product doesn't exist 16 } 17 18 var totalReviews = products[productId].Count; 19 var flaggedReviews = products[productId].Count(r => r.Value.Flagged); 20 var totalRating = products[productId].Where(r => !r.Value.Flagged).Sum(r => r.Value.Rating); 21 var reviewTexts = products[productId].Where(r => !r.Value.Flagged).Select(r => r.Value.Text).ToList(); 22 23 var averageRating = flaggedReviews == totalReviews ? 0 : totalRating / (totalReviews - flaggedReviews); 24 25 return new ReviewAggregate 26 { 27 TotalReviews = totalReviews, 28 FlaggedReviews = flaggedReviews, 29 AverageRating = averageRating, 30 ReviewTexts = reviewTexts 31 }; 32 } 33} 34 35public class Review 36{ 37 public string Text { get; set; } 38 public int Rating { get; set; } 39 public bool Flagged { get; set; } 40} 41 42public class ReviewAggregate 43{ 44 public int TotalReviews { get; set; } 45 public int FlaggedReviews { get; set; } 46 public double AverageRating { get; set; } 47 public List<string> ReviewTexts { get; set; } 48} 49 50public class Program 51{ 52 public static void Main() 53 { 54 ReviewManager reviewManager = new ReviewManager(); 55 56 // Adding some reviews 57 reviewManager.addReview("p1", "r1", "Great product!", 5); 58 reviewManager.addReview("p1", "r2", "Not bad", 3); 59 reviewManager.addReview("p1", "r3", "Terrible", 1); 60 61 // Flagging a review 62 reviewManager.flagReview("p1", "r3"); 63 64 // Testing the aggregation method 65 var aggregate = reviewManager.aggregateReviews("p1"); 66 if (aggregate != null) 67 { 68 Console.WriteLine($"Total Reviews: {aggregate.TotalReviews}, Flagged Reviews: {aggregate.FlaggedReviews}, Average Rating: {aggregate.AverageRating}"); 69 Console.WriteLine("Review Texts: " + string.Join(", ", aggregate.ReviewTexts)); 70 } 71 } 72}
In this step, the aggregateReviews
method is added to the ReviewManager
class. This 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!