From 03f169cd9688504b7aba83a820a427d7881bbdac Mon Sep 17 00:00:00 2001 From: static Date: Thu, 3 Oct 2024 19:14:08 +0000 Subject: [PATCH] Assignment 3 Done --- .../assignment03/custom_operators.rs | 17 ++- src/assignments/assignment03/parse_shell.rs | 27 +++- .../assignment03/small_exercises.rs | 116 +++++++++++++++++- 3 files changed, 150 insertions(+), 10 deletions(-) diff --git a/src/assignments/assignment03/custom_operators.rs b/src/assignments/assignment03/custom_operators.rs index b1c7aea..7183b47 100644 --- a/src/assignments/assignment03/custom_operators.rs +++ b/src/assignments/assignment03/custom_operators.rs @@ -26,7 +26,10 @@ pub enum MyOption { /// assert_eq!(my_map(MyOption::MyNone, len), MyOption::MyNone); /// ``` pub fn my_map U>(v: MyOption, f: F) -> MyOption { - todo!() + match v { + MyOption::MySome(value) => MyOption::MySome(f(value)), + _ => MyOption::MyNone, + } } /// Returns `MyNone` if the option is `MyNone`, otherwise calls `f` with the wrapped value and @@ -52,7 +55,10 @@ pub fn my_map U>(v: MyOption, f: F) -> MyOption { /// assert_eq!(my_and_then(MyOption::MyNone, pos_then_to_string), MyOption::MyNone); /// ``` pub fn my_and_then MyOption>(v: MyOption, f: F) -> MyOption { - todo!() + match v { + MyOption::MySome(value) => f(value), + _ => MyOption::MyNone, + } } /// Custom operator: `option_op_or(v1, v2, f)`. If neither `v1` nor `v2` is `Some`, returns `None`. @@ -76,5 +82,10 @@ pub fn my_option_op_or T>( v2: MyOption, f: F, ) -> MyOption { - todo!() + match (v1, v2) { + (MyOption::MySome(value1), MyOption::MySome(value2)) => MyOption::MySome(f(value1, value2)), + (MyOption::MySome(value1), _) => MyOption::MySome(value1), + (_, MyOption::MySome(value2)) => MyOption::MySome(value2), + (_, _) => MyOption::MyNone, + } } diff --git a/src/assignments/assignment03/parse_shell.rs b/src/assignments/assignment03/parse_shell.rs index ed2d1f3..b787cf1 100644 --- a/src/assignments/assignment03/parse_shell.rs +++ b/src/assignments/assignment03/parse_shell.rs @@ -27,5 +27,30 @@ /// /// See `test_shell` for more examples. pub fn parse_shell_command(command: &str) -> Vec { - todo!() + let mut result: Vec = Vec::new(); + let mut is_quote_open = false; + + for word in command.split_ascii_whitespace() { + let old_is_quote_open = is_quote_open; + + let content = if let Some(other) = word.strip_prefix("'") { + is_quote_open = !is_quote_open; + other + } else if let Some(other) = word.strip_suffix("'") { + is_quote_open = !is_quote_open; + other + } else { + word + }; + + if old_is_quote_open { + let last = result.last_mut().unwrap(); + last.push(' '); + last.push_str(content); + } else { + result.push(content.to_string()); + } + } + + result } diff --git a/src/assignments/assignment03/small_exercises.rs b/src/assignments/assignment03/small_exercises.rs index 62a8381..d7425f3 100644 --- a/src/assignments/assignment03/small_exercises.rs +++ b/src/assignments/assignment03/small_exercises.rs @@ -2,6 +2,7 @@ use std::collections::{HashMap, HashSet}; use std::fmt; +use std::hash::Hash; /// Day of week. #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -26,7 +27,13 @@ pub enum DayOfWeek { /// /// `next_weekday(Thu)` is `Fri`; and `next_weekday(Fri)` is `Mon`. pub fn next_weekday(day: DayOfWeek) -> DayOfWeek { - todo!() + match day { + DayOfWeek::Mon => DayOfWeek::Tue, + DayOfWeek::Tue => DayOfWeek::Wed, + DayOfWeek::Wed => DayOfWeek::Thu, + DayOfWeek::Thu => DayOfWeek::Fri, + _ => DayOfWeek::Mon, + } } /// Given a list of integers, returns its median (when sorted, the value in the middle position). @@ -52,7 +59,14 @@ pub fn next_weekday(day: DayOfWeek) -> DayOfWeek { /// /// Returns `None` if the list is empty. pub fn median(values: Vec) -> Option { - todo!() + if values.is_empty() { + return None; + } + + let mut values = values.to_vec(); + values.sort(); + + Some(values[values.len() / 2]) } /// Given a list of integers, returns its smallest mode (the value that occurs most often; a hash @@ -60,7 +74,32 @@ pub fn median(values: Vec) -> Option { /// /// Returns `None` if the list is empty. pub fn mode(values: Vec) -> Option { - todo!() + if values.is_empty() { + return None; + } + + let mut map: HashMap = HashMap::new(); + + for value in values { + *map.entry(value).or_insert(0) += 1; + } + + let mut mode: Option = None; + let mut mode_count = 0; + + for (key, value) in map { + if let Some(mode_value) = mode { + if mode_count < value || (mode_count == value && mode_value > key) { + mode = Some(key); + mode_count = value; + } + } else { + mode = Some(key); + mode_count = value; + } + } + + mode } /// Converts the given string to Pig Latin. Use the rules below to translate normal English into Pig @@ -83,7 +122,25 @@ pub fn mode(values: Vec) -> Option { /// /// You may assume the string only contains lowercase alphabets, and it contains at least one vowel. pub fn piglatin(input: String) -> String { - todo!() + let is_vowel = |c: u8| matches!(c, b'a' | b'e' | b'i' | b'o' | b'u'); + let input_bytes = input.as_bytes(); + + if is_vowel(input_bytes[0]) { + input + "hay" + } else if is_vowel(input_bytes[1]) { + let mut result = input[1..].to_string(); + result.push(input_bytes[0] as char); + result.push_str("ay"); + + result + } else { + for i in 1..input.len() { + if is_vowel(input_bytes[i]) { + return input[i..].to_string() + &input[0..i] + "ay"; + } + } + panic!(); + } } /// Converts HR commands to the organization table. @@ -109,7 +166,42 @@ pub fn piglatin(input: String) -> String { /// /// See the test function for more details. pub fn organize(commands: Vec) -> HashMap> { - todo!() + let mut result: HashMap> = HashMap::new(); + + for command in commands { + if let Some(other) = command.strip_prefix("Add ") { + let args: Vec = other.split(" to ").map(String::from).collect(); + _ = result + .entry(args[1].clone()) + .or_default() + .insert(args[0].clone()); + } else if let Some(other) = command.strip_prefix("Remove ") { + let args: Vec = other.split(" from ").map(String::from).collect(); + if let Some(set) = result.get_mut(&args[1]) { + _ = set.remove(&args[0]); + if set.is_empty() { + let _unused = result.remove(&args[1]); + } + } + } else if let Some(other) = command.strip_prefix("Move ") { + let args1: Vec = other.split(" from ").map(String::from).collect(); + let args2: Vec = args1[1].split(" to ").map(String::from).collect(); + + if let Some(set) = result.get_mut(&args2[0]) { + if set.remove(&args1[0]) { + if set.is_empty() { + let _unused = result.remove(&args2[0]); + } + _ = result + .entry(args2[1].clone()) + .or_default() + .insert(args1[0].clone()); + } + } + } + } + + result } /// Events in a text editor. @@ -130,5 +222,17 @@ pub enum TypeEvent { /// /// See the test function `test_editor` for examples. pub fn use_editor(events: Vec) -> String { - todo!() + let mut result = String::new(); + let mut clipboard = String::new(); + + for event in events { + match event { + TypeEvent::Type(value) => result.push(value), + TypeEvent::Backspace => _ = result.pop(), + TypeEvent::Copy => clipboard = result.clone(), + TypeEvent::Paste => result.push_str(&clipboard), + } + } + + result }