/** * [2353] Design a Food Rating System */ pub struct Solution {} // submission codes start here use std::cmp::Ordering; use std::collections::{BinaryHeap, HashMap}; #[derive(Debug, Clone, Eq, PartialEq)] struct Food { name: String, cuisine: String, rating: i32, } impl Food { fn new(name: String, cuisine: String, rating: i32) -> Self { Self { name, cuisine, rating, } } fn update_rating(&self, new_rating: i32) -> Self { Self { name: self.name.clone(), cuisine: self.cuisine.clone(), rating: new_rating, } } } impl Ord for Food { fn cmp(&self, other: &Self) -> Ordering { match self.rating.cmp(&other.rating) { Ordering::Equal => other.name.cmp(&self.name), a => a, } } } impl PartialOrd for Food { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } struct FoodRatings { food_map: HashMap, cuisine_heap: HashMap>, } /** * `&self` means the method takes an immutable reference. * If you need a mutable reference, change it to `&mut self` instead. */ impl FoodRatings { fn new(foods: Vec, cuisines: Vec, ratings: Vec) -> Self { let mut food_map = HashMap::new(); let mut cuisine_heap = HashMap::new(); for ((name, cuisine), &rating) in foods.iter().zip(cuisines.iter()).zip(ratings.iter()) { food_map.insert( name.clone(), Food::new(name.clone(), cuisine.clone(), rating), ); let heap = cuisine_heap .entry(cuisine.clone()) .or_insert(BinaryHeap::new()); heap.push(Food::new(name.clone(), cuisine.clone(), rating.clone())); } Self { food_map, cuisine_heap, } } fn change_rating(&mut self, food: String, new_rating: i32) { let food_entry = self.food_map.get_mut(&food).unwrap(); food_entry.rating = new_rating; let heap = self.cuisine_heap.get_mut(&food_entry.cuisine).unwrap(); heap.push(food_entry.update_rating(new_rating)); } fn highest_rated(&mut self, cuisine: String) -> String { let heap = self.cuisine_heap.get_mut(&cuisine).unwrap(); while let Some(head) = heap.peek() { let food_entry = self.food_map.get(&head.name).unwrap(); if head.rating == food_entry.rating { return food_entry.name.clone(); } heap.pop(); } "".to_owned() } } /** * Your FoodRatings object will be instantiated and called as such: * let obj = FoodRatings::new(foods, cuisines, ratings); * obj.change_rating(food, newRating); * let ret_2: String = obj.highest_rated(cuisine); */ // submission codes end #[cfg(test)] mod tests { use super::*; #[test] fn test_2353() { let mut ratings = FoodRatings::new( vec_string!("kimchi", "miso", "sushi", "moussaka", "ramen", "bulgogi"), vec_string!("korean", "japanese", "japanese", "greek", "japanese", "korean"), vec![9, 12, 8, 15, 14, 7], ); assert_eq!("kimchi", ratings.highest_rated("korean".to_owned())); assert_eq!("ramen", ratings.highest_rated("japanese".to_owned())); ratings.change_rating("sushi".to_owned(), 16); assert_eq!("sushi", ratings.highest_rated("japanese".to_owned())); ratings.change_rating("ramen".to_owned(), 16); assert_eq!("ramen", ratings.highest_rated("japanese".to_owned())); } }