├── .gitignore ├── Cargo.toml ├── README.md ├── rust-logo-mozilla.jpg └── src ├── exercises ├── arguments_optional.rs ├── binary_agents.rs ├── convert_html_entities.rs ├── diff_two_arrays.rs ├── dna_pairing.rs ├── drop_it.rs ├── everything_be_true.rs ├── make_a_person.rs ├── map_the_debris.rs ├── missing_letters.rs ├── mod.rs ├── pig_latin.rs ├── search_and_replace.rs ├── seek_and_destroy.rs ├── smallest_common_multiple.rs ├── sorted_union.rs ├── spinal_tab_case.rs ├── steamroller.rs ├── sum_all_numbers_in_range.rs ├── sum_all_primes.rs ├── sum_odd_fibonacci_numbers.rs └── wherefore_art_thou.rs ├── main.rs └── solutions ├── arguments_optional.rs ├── binary_agents.rs ├── convert_html_entities.rs ├── diff_two_arrays.rs ├── dna_pairing.rs ├── drop_it.rs ├── everything_be_true.rs ├── make_a_person.rs ├── map_the_debris.rs ├── missing_letters.rs ├── mod.rs ├── pig_latin.rs ├── search_and_replace.rs ├── seek_and_destroy.rs ├── smallest_common_multiple.rs ├── sorted_union.rs ├── spinal_tab_case.rs ├── steamroller.rs ├── sum_all_numbers_in_range.rs ├── sum_all_primes.rs ├── sum_odd_fibonacci_numbers.rs └── wherefore_art_thou.rs /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fcc" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | regex = "1" 10 | colored = "2.0.0" 11 | cli-table = "0.4" 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Rust Algorithms and Data Structures 2 | 3 | This is a Rust equivalent to [FreeCodeCamp's JavaScript Algorithms and Data Structures course](https://www.freecodecamp.org/learn/javascript-algorithms-and-data-structures/) (section ["Intermediate Algorithm Scripting"](https://www.freecodecamp.org/learn/javascript-algorithms-and-data-structures/#intermediate-algorithm-scripting)). 4 | 5 | ## Install 6 | 7 | First clone the repository to your desired destination: 8 | 9 | ``` 10 | git clone git@github.com:3rfaan/rust_algorithms.git && cd rust_algorithms 11 | ``` 12 | 13 | Then you can run the following command while in the folder `rust_algorithms`: 14 | 15 | ``` 16 | cargo run 17 | ``` 18 | 19 | There will be a list of all exercises in the same order as on the FCC website. You can then enter the number of the exercise you want to see the tests. If you want to see the result of all tests just type in `all`. To exit the program type `0`. 20 | -------------------------------------------------------------------------------- /rust-logo-mozilla.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/3rfaan/rust_algorithms/c5bf3878f138f0fd9c248709187a67d64f41be29/rust-logo-mozilla.jpg -------------------------------------------------------------------------------- /src/exercises/arguments_optional.rs: -------------------------------------------------------------------------------- 1 | // Create a function that sums two arguments together. If only one argument is provided, 2 | // then return a function that expects one argument and returns the sum. 3 | // 4 | // For example, addTogether(2, 3) should return 5, and addTogether(2) should return a function. 5 | // 6 | // Calling this returned function with a single argument will then return the sum: 7 | // 8 | // var sumTwoAnd = addTogether(2); 9 | // 10 | // sumTwoAnd(3) returns 5. 11 | // 12 | // If either argument isn't a valid number, return undefined. 13 | 14 | #[allow(dead_code)] 15 | #[allow(unused_variables)] 16 | fn curry(a: i32) -> impl Fn(i32) -> i32 { 17 | move |x| unimplemented!() 18 | } 19 | 20 | #[allow(dead_code)] 21 | #[allow(unused_variables)] 22 | fn add_two(a: i32, b: i32) -> i32 { 23 | unimplemented!() 24 | } 25 | 26 | #[cfg(test)] 27 | mod tests { 28 | use super::*; 29 | 30 | #[test] 31 | fn test1() { 32 | assert_eq!(add_two(2, 3), 5); 33 | } 34 | 35 | #[test] 36 | fn test2() { 37 | assert_eq!(add_two(23, 30), 53); 38 | } 39 | 40 | #[test] 41 | fn test3() { 42 | let add_five = curry(5); 43 | 44 | assert_eq!(add_five(7), 12); 45 | } 46 | 47 | #[test] 48 | fn test4() { 49 | let add_twentyfive = curry(25); 50 | 51 | assert_eq!(add_twentyfive(50), 75); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/exercises/binary_agents.rs: -------------------------------------------------------------------------------- 1 | // Return an English translated sentence of the passed binary string. 2 | 3 | // The binary string will be space separated. 4 | 5 | #[allow(dead_code)] 6 | #[allow(unused_variables)] 7 | fn binary_agent(s: &str) -> String { 8 | unimplemented!() 9 | } 10 | 11 | #[cfg(test)] 12 | mod tests { 13 | use super::*; 14 | 15 | #[test] 16 | fn test1() { 17 | assert_eq!(binary_agent("01000001 01110010 01100101 01101110 00100111 01110100 00100000 01100010 01101111 01101110 01100110 01101001 01110010 01100101 01110011 00100000 01100110 01110101 01101110 00100001 00111111"), "Aren't bonfires fun!?"); 18 | } 19 | 20 | #[test] 21 | fn test2() { 22 | assert_eq!(binary_agent("01001001 00100000 01101100 01101111 01110110 01100101 00100000 01000110 01110010 01100101 01100101 01000011 01101111 01100100 01100101 01000011 01100001 01101101 01110000 00100001"), "I love FreeCodeCamp!"); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/exercises/convert_html_entities.rs: -------------------------------------------------------------------------------- 1 | // Convert the characters &, <, >, " (double quote), and ' (apostrophe), 2 | // in a string to their corresponding HTML entities. 3 | 4 | // Some characters and their corresponding HTML entities 5 | #[allow(dead_code)] 6 | #[allow(unused_variables)] 7 | fn convert_html(s: &str) -> String { 8 | unimplemented!() 9 | } 10 | 11 | #[cfg(test)] 12 | mod tests { 13 | use super::*; 14 | 15 | #[test] 16 | fn test1() { 17 | assert_eq!(convert_html("Dolce & Gabbana"), "Dolce & Gabbana"); 18 | } 19 | 20 | #[test] 21 | fn test2() { 22 | assert_eq!( 23 | convert_html("Hamburgers < Pizza < Tacos"), 24 | "Hamburgers < Pizza < Tacos" 25 | ); 26 | } 27 | 28 | #[test] 29 | fn test3() { 30 | assert_eq!(convert_html("Sixty > twelve"), "Sixty > twelve"); 31 | } 32 | 33 | #[test] 34 | fn test4() { 35 | assert_eq!( 36 | convert_html("Stuff in \"quotation marks\""), 37 | "Stuff in "quotation marks"" 38 | ); 39 | } 40 | 41 | #[test] 42 | fn test5() { 43 | assert_eq!(convert_html("Schindler's List"), "Schindler's List"); 44 | } 45 | 46 | #[test] 47 | fn test6() { 48 | assert_eq!(convert_html("<>"), "<>"); 49 | } 50 | 51 | #[test] 52 | fn test7() { 53 | assert_eq!(convert_html("abc"), "abc"); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/exercises/diff_two_arrays.rs: -------------------------------------------------------------------------------- 1 | // Compare two arrays and return a new array with any items only found in one of the two given arrays, 2 | // but not both. In other words, return the symmetric difference of the two arrays. 3 | 4 | // Note: You can return the array with its elements in any order. 5 | 6 | #[allow(dead_code)] 7 | #[allow(unused_variables)] 8 | fn diff_array<'a>(arr1: Vec<&'a str>, arr2: Vec<&'a str>) -> Vec<&'a str> { 9 | unimplemented!() 10 | } 11 | 12 | #[cfg(test)] 13 | mod tests { 14 | use super::*; 15 | 16 | #[test] 17 | fn test1() { 18 | let arr1 = vec![ 19 | "diorite", 20 | "andesite", 21 | "grass", 22 | "dirt", 23 | "pink wool", 24 | "dead shrub", 25 | ]; 26 | let arr2 = vec!["diorite", "andesite", "grass", "dirt", "dead shrub"]; 27 | 28 | assert_eq!(diff_array(arr1, arr2), ["pink wool"]); 29 | } 30 | 31 | #[test] 32 | fn test2() { 33 | let arr1 = vec!["andesite", "grass", "dirt", "pink wool", "dead shrub"]; 34 | let arr2 = vec!["diorite", "andesite", "grass", "dirt", "dead shrub"]; 35 | let mut answer = diff_array(arr1, arr2); 36 | answer.sort_unstable(); 37 | assert_eq!(answer, ["diorite", "pink wool"]); 38 | } 39 | 40 | #[test] 41 | fn test3() { 42 | let arr1 = vec!["andesite", "grass", "dirt", "dead shrub"]; 43 | let arr2 = vec!["andesite", "grass", "dirt", "dead shrub"]; 44 | 45 | assert_eq!(diff_array(arr1, arr2).len(), 0); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/exercises/dna_pairing.rs: -------------------------------------------------------------------------------- 1 | // Pairs of DNA strands consist of nucleobase pairs. Base pairs are represented by the characters AT and CG, 2 | // which form building blocks of the DNA double helix. 3 | 4 | // The DNA strand is missing the pairing element. Write a function to match the missing base pairs for the provided DNA strand. 5 | // For each character in the provided string, find the base pair character. Return the results as a 2d array. 6 | 7 | // For example, for the input GCG, return [["G", "C"], ["C","G"], ["G", "C"]] 8 | 9 | // The character and its pair are paired up in an array, and all the arrays are grouped into one encapsulating array. 10 | 11 | #[allow(dead_code)] 12 | #[allow(unused_variables)] 13 | fn pair_element(s: &str) -> Vec<[char; 2]> { 14 | unimplemented!() 15 | } 16 | 17 | // Function to return an array of 2 chars with the matching base DNA pair 18 | #[allow(dead_code)] 19 | #[allow(unused_variables)] 20 | fn match_base_pair(c: char) -> [char; 2] { 21 | match c { 22 | 'A' => ['A', 'T'], 23 | 'T' => ['T', 'A'], 24 | 'C' => ['C', 'G'], 25 | 'G' => ['G', 'C'], 26 | _ => panic!("Invalid DNA character: {c}"), 27 | } 28 | } 29 | 30 | #[cfg(test)] 31 | mod tests { 32 | use super::*; 33 | 34 | #[test] 35 | fn test1() { 36 | assert_eq!( 37 | pair_element("ATCGA"), 38 | vec![['A', 'T'], ['T', 'A'], ['C', 'G'], ['G', 'C'], ['A', 'T']] 39 | ); 40 | } 41 | 42 | #[test] 43 | fn test2() { 44 | assert_eq!( 45 | pair_element("TTGAG"), 46 | vec![['T', 'A'], ['T', 'A'], ['G', 'C'], ['A', 'T'], ['G', 'C']], 47 | ) 48 | } 49 | 50 | #[test] 51 | fn test3() { 52 | assert_eq!( 53 | pair_element("CTCTA"), 54 | vec![['C', 'G'], ['T', 'A'], ['C', 'G'], ['T', 'A'], ['A', 'T']], 55 | ) 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/exercises/drop_it.rs: -------------------------------------------------------------------------------- 1 | // Given the array arr, iterate through and remove each element starting from the first element (the 0 index) 2 | // until the function func returns true when the iterated element is passed through it. 3 | 4 | // Then return the rest of the array once the condition is satisfied, 5 | // otherwise, arr should be returned as an empty array. 6 | 7 | #[allow(dead_code)] 8 | #[allow(unused_variables)] 9 | fn drop_elements(arr: &mut Vec, filter: F) -> Vec 10 | where 11 | F: Fn(&i32) -> bool, 12 | { 13 | unimplemented!() 14 | } 15 | 16 | #[cfg(test)] 17 | mod tests { 18 | use super::*; 19 | 20 | #[test] 21 | fn test1() { 22 | assert_eq!( 23 | drop_elements(&mut vec![1, 2, 3, 4], |&n| n >= 3), 24 | vec![3, 4] 25 | ); 26 | } 27 | 28 | #[test] 29 | fn test2() { 30 | assert_eq!( 31 | drop_elements(&mut vec![0, 1, 0, 1], |&n| n == 1), 32 | vec![1, 0, 1] 33 | ); 34 | } 35 | 36 | #[test] 37 | fn test3() { 38 | assert_eq!(drop_elements(&mut vec![1, 2, 3], |&n| n > 0), vec![1, 2, 3]); 39 | } 40 | 41 | #[test] 42 | fn test4() { 43 | assert_eq!(drop_elements(&mut vec![1, 2, 3, 4], |&n| n > 5), vec![]); 44 | } 45 | 46 | #[test] 47 | fn test5() { 48 | assert_eq!( 49 | drop_elements(&mut vec![1, 2, 3, 7, 4], |&n| n > 3), 50 | vec![7, 4] 51 | ); 52 | } 53 | 54 | #[test] 55 | fn test6() { 56 | assert_eq!( 57 | drop_elements(&mut vec![1, 2, 3, 9, 2], |&n| n > 2), 58 | vec![3, 9, 2] 59 | ); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/exercises/everything_be_true.rs: -------------------------------------------------------------------------------- 1 | // Check if the predicate (second argument) is truthy on all elements of a collection (first argument). 2 | 3 | // In other words, you are given an array collection of objects. 4 | // The predicate pre will be an object property and you need to return true if its value is truthy. Otherwise, return false. 5 | 6 | // In JavaScript, truthy values are values that translate to true when evaluated in a Boolean context. 7 | 8 | // Remember, you can access object properties through either dot notation or [] notation. 9 | 10 | // Enum to hold Person or Pokemon type so both types can be passed as argument for truth_check() 11 | #[derive(PartialEq)] 12 | #[allow(dead_code)] 13 | #[allow(unused_variables)] 14 | enum Type { 15 | Person(Person), 16 | Pokemon(Pokemon), 17 | } 18 | 19 | // Methods returning value of certain field 20 | impl Type {} 21 | 22 | #[derive(PartialEq)] 23 | #[allow(unused_variables)] 24 | struct Person { 25 | name: String, 26 | role: String, 27 | is_bot: bool, 28 | } 29 | 30 | #[derive(PartialEq)] 31 | #[allow(unused_variables)] 32 | struct Pokemon { 33 | name: String, 34 | number: i32, 35 | caught: i32, 36 | } 37 | 38 | #[allow(dead_code)] 39 | #[allow(unused_variables)] 40 | fn truth_check(collection: Vec, pre: &str) -> bool { 41 | unimplemented!() 42 | } 43 | 44 | #[cfg(test)] 45 | mod tests { 46 | use super::*; 47 | 48 | #[test] 49 | fn test1() { 50 | let p1: Person = Person { 51 | name: String::from("Quincy"), 52 | role: String::from("Founder"), 53 | is_bot: false, 54 | }; 55 | 56 | let p2: Person = Person { 57 | name: String::from("Naomi"), 58 | role: String::from(""), 59 | is_bot: false, 60 | }; 61 | 62 | let p3: Person = Person { 63 | name: String::from("Camperbot"), 64 | role: String::from("Bot"), 65 | is_bot: true, 66 | }; 67 | 68 | let collection = vec![Type::Person(p1), Type::Person(p2), Type::Person(p3)]; 69 | 70 | assert_eq!(truth_check(collection, "is_bot"), false); 71 | } 72 | 73 | #[test] 74 | fn test2() { 75 | let p1: Person = Person { 76 | name: String::from("Quincy"), 77 | role: String::from("Founder"), 78 | is_bot: false, 79 | }; 80 | 81 | let p2: Person = Person { 82 | name: String::from("Naomi"), 83 | role: String::from(""), 84 | is_bot: false, 85 | }; 86 | 87 | let p3: Person = Person { 88 | name: String::from("Camperbot"), 89 | role: String::from("Bot"), 90 | is_bot: true, 91 | }; 92 | 93 | let collection = vec![Type::Person(p1), Type::Person(p2), Type::Person(p3)]; 94 | 95 | assert_eq!(truth_check(collection, "name"), true); 96 | } 97 | 98 | #[test] 99 | fn test3() { 100 | let p1: Person = Person { 101 | name: String::from("Quincy"), 102 | role: String::from("Founder"), 103 | is_bot: false, 104 | }; 105 | 106 | let p2: Person = Person { 107 | name: String::from("Naomi"), 108 | role: String::from(""), 109 | is_bot: false, 110 | }; 111 | 112 | let p3: Person = Person { 113 | name: String::from("Camperbot"), 114 | role: String::from("Bot"), 115 | is_bot: true, 116 | }; 117 | 118 | let collection = vec![Type::Person(p1), Type::Person(p2), Type::Person(p3)]; 119 | 120 | assert_eq!(truth_check(collection, "role"), false); 121 | } 122 | 123 | #[test] 124 | fn test4() { 125 | let pkmn1: Pokemon = Pokemon { 126 | name: String::from("Pikachu"), 127 | number: 25, 128 | caught: 3, 129 | }; 130 | 131 | let pkmn2: Pokemon = Pokemon { 132 | name: String::from("Togepi"), 133 | number: 175, 134 | caught: 1, 135 | }; 136 | 137 | let collection = vec![Type::Pokemon(pkmn1), Type::Pokemon(pkmn2)]; 138 | 139 | assert_eq!(truth_check(collection, "number"), true); 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /src/exercises/make_a_person.rs: -------------------------------------------------------------------------------- 1 | // Fill in the object constructor with the following methods below: 2 | // 3 | // getFirstName() 4 | // getLastName() 5 | // getFullName() 6 | // setFirstName(first) 7 | // setLastName(last) 8 | // setFullName(firstAndLast) 9 | // 10 | // Run the tests to see the expected output for each method. 11 | // The methods that take an argument must accept only one argument and it has to be a string. 12 | // These methods must be the only available means of interacting with the object. 13 | 14 | #[allow(dead_code)] 15 | #[allow(unused_variables)] 16 | struct Person {} 17 | 18 | #[allow(dead_code)] 19 | #[allow(unused_variables)] 20 | impl Person { 21 | fn create(first_name: &str, last_name: &str) -> Self { 22 | unimplemented!() 23 | } 24 | 25 | fn get_first_name(&self) -> &str { 26 | unimplemented!() 27 | } 28 | 29 | fn get_last_name(&self) -> &str { 30 | unimplemented!() 31 | } 32 | 33 | fn get_full_name(&self) -> String { 34 | unimplemented!() 35 | } 36 | 37 | fn set_first_name(&mut self, first_name: &str) { 38 | unimplemented!() 39 | } 40 | 41 | fn set_last_name(&mut self, last_name: &str) { 42 | unimplemented!() 43 | } 44 | 45 | fn set_full_name(&mut self, first_name: &str, last_name: &str) { 46 | unimplemented!() 47 | } 48 | } 49 | 50 | #[cfg(test)] 51 | mod tests { 52 | use super::*; 53 | 54 | #[test] 55 | fn test1() { 56 | let bob = Person::create("Bob", "Ross"); 57 | 58 | assert_eq!(bob.get_first_name(), "Bob"); 59 | } 60 | 61 | #[test] 62 | fn test2() { 63 | let bob = Person::create("Bob", "Ross"); 64 | 65 | assert_eq!(bob.get_last_name(), "Ross"); 66 | } 67 | 68 | #[test] 69 | fn test3() { 70 | let bob = Person::create("Bob", "Ross"); 71 | 72 | assert_eq!(bob.get_full_name(), "Bob Ross".to_string()); 73 | } 74 | 75 | #[test] 76 | fn test4() { 77 | let mut bob = Person::create("Bob", "Ross"); 78 | 79 | bob.set_first_name("Haskell"); 80 | 81 | assert_eq!(bob.get_full_name(), "Haskell Ross".to_string()); 82 | } 83 | 84 | #[test] 85 | fn test5() { 86 | let mut bob = Person::create("Bob", "Ross"); 87 | 88 | bob.set_first_name("Haskell"); 89 | bob.set_last_name("Curry"); 90 | 91 | assert_eq!(bob.get_full_name(), "Haskell Curry".to_string()); 92 | } 93 | 94 | #[test] 95 | fn test6() { 96 | let mut bob = Person::create("Bob", "Ross"); 97 | 98 | bob.set_full_name("Haskell", "Curry"); 99 | 100 | assert_eq!(bob.get_full_name(), "Haskell Curry".to_string()); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/exercises/map_the_debris.rs: -------------------------------------------------------------------------------- 1 | // According to Kepler's Third Law, the orbital period T of two point masses orbiting 2 | // each other in a circular or elliptic orbit is: 3 | // 4 | // T=2π√a^3/μ 5 | // 6 | // - a is the orbit's semi-major axis 7 | // - μ=GM is the standard gravitational parameter 8 | // - G is the gravitational constant, 9 | // - M is the mass of the more massive body. 10 | // 11 | // Return a new array that transforms the elements' average altitude into their orbital periods (in seconds). 12 | 13 | // The array will contain objects in the format {name: 'name', avgAlt: avgAlt}. 14 | // 15 | // The values should be rounded to the nearest whole number. The body being orbited is Earth. 16 | // 17 | // The radius of the earth is 6367.4447 kilometers, and the GM value of earth is 398600.4418 km^3s^-2. 18 | 19 | #[allow(dead_code)] 20 | #[allow(unused_variables)] 21 | #[derive(Debug, PartialEq)] 22 | struct Satellite { 23 | name: String, 24 | avg_alt: f64, 25 | } 26 | 27 | #[allow(dead_code)] 28 | #[allow(unused_variables)] 29 | fn orbital_period(arr: Vec) -> Vec<(String, i32)> { 30 | unimplemented!() 31 | } 32 | 33 | #[cfg(test)] 34 | mod tests { 35 | use super::*; 36 | 37 | #[test] 38 | fn test1() { 39 | let sputnik = Satellite { 40 | name: "sputnik".to_string(), 41 | avg_alt: 35873.5553, 42 | }; 43 | 44 | assert_eq!( 45 | orbital_period(vec![sputnik]), 46 | vec![("sputnik".to_string(), 86400)] 47 | ); 48 | } 49 | 50 | #[test] 51 | fn test2() { 52 | let iss = Satellite { 53 | name: "iss".to_string(), 54 | avg_alt: 413.6, 55 | }; 56 | let hubble = Satellite { 57 | name: "hubble".to_string(), 58 | avg_alt: 556.7, 59 | }; 60 | let moon = Satellite { 61 | name: "moon".to_string(), 62 | avg_alt: 378632.553, 63 | }; 64 | 65 | let result = vec![ 66 | ("iss".to_string(), 5557), 67 | ("hubble".to_string(), 5734), 68 | ("moon".to_string(), 2377399), 69 | ]; 70 | 71 | assert_eq!(orbital_period(vec![iss, hubble, moon]), result) 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/exercises/missing_letters.rs: -------------------------------------------------------------------------------- 1 | // Find the missing letter in the passed letter range and return it. 2 | 3 | // If all letters are present in the range, return undefined. 4 | 5 | #[allow(dead_code)] 6 | #[allow(unused_variables)] 7 | fn fear_not_letter(s: &str) -> Option { 8 | unimplemented!() 9 | } 10 | 11 | #[cfg(test)] 12 | mod tests { 13 | use super::*; 14 | 15 | #[test] 16 | fn test1() { 17 | assert_eq!(fear_not_letter("abce"), Some('d')); 18 | } 19 | 20 | #[test] 21 | fn test2() { 22 | assert_eq!(fear_not_letter("abcdefghjklmno"), Some('i')); 23 | } 24 | 25 | #[test] 26 | fn test3() { 27 | assert_eq!(fear_not_letter("stvwx"), Some('u')); 28 | } 29 | 30 | #[test] 31 | fn test4() { 32 | assert_eq!(fear_not_letter("bcdf"), Some('e')); 33 | } 34 | 35 | #[test] 36 | fn test5() { 37 | assert_eq!(fear_not_letter("abcdefghijklmnopqrstuvwxyz"), None); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/exercises/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod arguments_optional; 2 | pub mod binary_agents; 3 | pub mod convert_html_entities; 4 | pub mod diff_two_arrays; 5 | pub mod dna_pairing; 6 | pub mod drop_it; 7 | pub mod everything_be_true; 8 | pub mod make_a_person; 9 | pub mod map_the_debris; 10 | pub mod missing_letters; 11 | pub mod pig_latin; 12 | pub mod search_and_replace; 13 | pub mod seek_and_destroy; 14 | pub mod smallest_common_multiple; 15 | pub mod sorted_union; 16 | pub mod spinal_tab_case; 17 | pub mod steamroller; 18 | pub mod sum_all_numbers_in_range; 19 | pub mod sum_all_primes; 20 | pub mod sum_odd_fibonacci_numbers; 21 | pub mod wherefore_art_thou; 22 | -------------------------------------------------------------------------------- /src/exercises/pig_latin.rs: -------------------------------------------------------------------------------- 1 | // Pig Latin is a way of altering English Words. The rules are as follows: 2 | 3 | // - If a word begins with a consonant, take the first consonant or consonant cluster, 4 | // move it to the end of the word, and add ay to it. 5 | 6 | // - If a word begins with a vowel, just add way at the end. 7 | 8 | // Translate the provided string to Pig Latin. Input strings are guaranteed to be English words in all lowercase. 9 | 10 | #[allow(dead_code)] 11 | #[allow(unused_variables)] 12 | fn translate_pig_latin(s: String) -> String { 13 | unimplemented!() 14 | } 15 | 16 | #[cfg(test)] 17 | mod tests { 18 | use super::*; 19 | 20 | #[test] 21 | fn test1() { 22 | assert_eq!( 23 | translate_pig_latin("california".to_string()), 24 | "aliforniacay" 25 | ); 26 | } 27 | 28 | #[test] 29 | fn test2() { 30 | assert_eq!( 31 | translate_pig_latin("paragraphs".to_string()), 32 | "aragraphspay" 33 | ); 34 | } 35 | 36 | #[test] 37 | fn test3() { 38 | assert_eq!(translate_pig_latin("glove".to_string()), "oveglay"); 39 | } 40 | 41 | #[test] 42 | fn test4() { 43 | assert_eq!(translate_pig_latin("algorithm".to_string()), "algorithmway"); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/exercises/search_and_replace.rs: -------------------------------------------------------------------------------- 1 | // Perform a search and replace on the sentence using the arguments provided and return the new sentence. 2 | 3 | // First argument is the sentence to perform the search and replace on. 4 | 5 | // Second argument is the word that you will be replacing (before). 6 | 7 | // Third argument is what you will be replacing the second argument with (after). 8 | 9 | // Note: Preserve the case of the first character in the original word when you are replacing it. 10 | // For example if you mean to replace the word Book with the word dog, it should be replaced as Dog 11 | 12 | #[allow(dead_code)] 13 | #[allow(unused_variables)] 14 | fn my_replace(s: &str, before: &str, after: &str) -> String { 15 | unimplemented!() 16 | } 17 | 18 | #[cfg(test)] 19 | mod tests { 20 | use super::*; 21 | 22 | #[test] 23 | fn test1() { 24 | assert_eq!( 25 | my_replace("Let us go to the store", "store", "mall"), 26 | "Let us go to the mall" 27 | ); 28 | } 29 | 30 | #[test] 31 | fn test2() { 32 | assert_eq!( 33 | my_replace("He is Sleeping on the couch", "Sleeping", "sitting"), 34 | "He is Sitting on the couch" 35 | ); 36 | } 37 | 38 | #[test] 39 | fn test3() { 40 | assert_eq!( 41 | my_replace("I think we should look up there", "up", "Down"), 42 | "I think we should look down there" 43 | ); 44 | } 45 | 46 | #[test] 47 | fn test4() { 48 | assert_eq!( 49 | my_replace("This has a spellngi error", "spellngi", "spelling"), 50 | "This has a spelling error" 51 | ); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/exercises/seek_and_destroy.rs: -------------------------------------------------------------------------------- 1 | // You will be provided with an initial array (the first argument in the destroyer function), 2 | // followed by one or more arguments. Remove all elements from the initial array that are of 3 | // the same value as these arguments. 4 | 5 | // Note: You have to use the arguments object. 6 | 7 | #[allow(dead_code)] 8 | #[allow(unused_variables)] 9 | fn destroyer(arr: &mut Vec, args: &[i32]) -> Vec { 10 | unimplemented!() 11 | } 12 | 13 | #[cfg(test)] 14 | mod tests { 15 | use super::*; 16 | 17 | #[test] 18 | fn test1() { 19 | let mut arr = vec![1, 2, 3, 1, 2, 3]; 20 | let args = vec![2, 3]; 21 | 22 | assert_eq!(destroyer(&mut arr, &args), [1, 1]); 23 | } 24 | 25 | #[test] 26 | fn test2() { 27 | let mut arr = vec![1, 2, 3, 5, 1, 2, 3]; 28 | let args = vec![2, 3]; 29 | 30 | assert_eq!(destroyer(&mut arr, &args), [1, 5, 1]); 31 | } 32 | 33 | #[test] 34 | fn test3() { 35 | let mut arr = vec![3, 5, 1, 2, 2]; 36 | let args = vec![2, 3, 5]; 37 | 38 | assert_eq!(destroyer(&mut arr, &args), [1]); 39 | } 40 | 41 | #[test] 42 | fn test4() { 43 | let mut arr = vec![2, 3, 2, 3]; 44 | let args = vec![2, 3]; 45 | 46 | assert_eq!(destroyer(&mut arr, &args).len(), 0); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/exercises/smallest_common_multiple.rs: -------------------------------------------------------------------------------- 1 | // Find the smallest common multiple of the provided parameters that can be evenly divided by both, 2 | // as well as by all sequential numbers in the range between these parameters. 3 | 4 | // The range will be an array of two numbers that will not necessarily be in numerical order. 5 | 6 | // For example, if given 1 and 3, find the smallest common multiple of both 1 and 3 that is also 7 | // evenly divisible by all numbers between 1 and 3. The answer here would be 6. 8 | 9 | #[allow(dead_code)] 10 | #[allow(unused_variables)] 11 | fn smallest_commons(arr: [i32; 2]) -> i32 { 12 | unimplemented!() 13 | } 14 | 15 | #[cfg(test)] 16 | mod tests { 17 | use super::*; 18 | 19 | #[test] 20 | fn test1() { 21 | assert_eq!(smallest_commons([1, 5]), 60); 22 | } 23 | 24 | #[test] 25 | fn test2() { 26 | assert_eq!(smallest_commons([5, 1]), 60); 27 | } 28 | 29 | #[test] 30 | fn test3() { 31 | assert_eq!(smallest_commons([2, 10]), 2520); 32 | } 33 | 34 | #[test] 35 | fn test4() { 36 | assert_eq!(smallest_commons([1, 13]), 360360); 37 | } 38 | 39 | #[test] 40 | fn test5() { 41 | assert_eq!(smallest_commons([23, 18]), 6056820); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/exercises/sorted_union.rs: -------------------------------------------------------------------------------- 1 | // Write a function that takes two or more arrays and returns a new array of unique values in the order of the original provided arrays. 2 | 3 | // In other words, all values present from all arrays should be included in their original order, but with no duplicates in the final array. 4 | 5 | // The unique numbers should be sorted by their original order, but the final array should not be sorted in numerical order. 6 | 7 | // Check the assertion tests for examples. 8 | 9 | #[allow(dead_code)] 10 | #[allow(unused_variables)] 11 | fn unite_unique(arr: Vec>) -> Vec { 12 | unimplemented!() 13 | } 14 | 15 | #[cfg(test)] 16 | mod tests { 17 | use super::*; 18 | 19 | #[test] 20 | fn test1() { 21 | assert_eq!( 22 | unite_unique([vec![1, 3, 2], vec![5, 2, 1, 4], vec![2, 1]].to_vec()), 23 | [1, 3, 2, 5, 4].to_vec() 24 | ); 25 | } 26 | 27 | #[test] 28 | fn test2() { 29 | assert_eq!( 30 | unite_unique([vec![1, 2, 3], vec![5, 2, 1]].to_vec()), 31 | [1, 2, 3, 5].to_vec() 32 | ); 33 | } 34 | 35 | #[test] 36 | fn test3() { 37 | assert_eq!( 38 | unite_unique([vec![1, 2, 3], vec![5, 2, 1, 4], vec![2, 1], vec![6, 7, 8]].to_vec()), 39 | [1, 2, 3, 5, 4, 6, 7, 8].to_vec() 40 | ); 41 | } 42 | 43 | #[test] 44 | fn test4() { 45 | assert_eq!( 46 | unite_unique([vec![1, 3, 2], vec![5, 4], vec![5, 6]].to_vec()), 47 | [1, 3, 2, 5, 4, 6].to_vec() 48 | ); 49 | } 50 | 51 | #[test] 52 | fn test5() { 53 | assert_eq!( 54 | unite_unique([vec![1, 3, 2, 3], vec![5, 2, 1, 4], vec![2, 1]].to_vec()), 55 | [1, 3, 2, 5, 4].to_vec() 56 | ); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/exercises/spinal_tab_case.rs: -------------------------------------------------------------------------------- 1 | // Convert a string to spinal case. Spinal case is all-lowercase-words-joined-by-dashes. 2 | 3 | #[allow(dead_code)] 4 | #[allow(unused_variables)] 5 | fn spinal_case(s: String) -> String { 6 | unimplemented!() 7 | } 8 | 9 | #[cfg(test)] 10 | mod tests { 11 | use super::*; 12 | 13 | #[test] 14 | fn test1() { 15 | assert_eq!( 16 | spinal_case("This Is Spinal Tap".to_string()), 17 | "this-is-spinal-tap" 18 | ); 19 | } 20 | 21 | #[test] 22 | fn test2() { 23 | assert_eq!( 24 | spinal_case("thisIsSpinalTap".to_string()), 25 | "this-is-spinal-tap" 26 | ); 27 | } 28 | 29 | #[test] 30 | fn test3() { 31 | assert_eq!( 32 | spinal_case("The_Andy_Griffith_Show".to_string()), 33 | "the-andy-griffith-show" 34 | ); 35 | } 36 | 37 | #[test] 38 | fn test4() { 39 | assert_eq!( 40 | spinal_case("Teletubbies say Eh-oh".to_string()), 41 | "teletubbies-say-eh-oh" 42 | ); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/exercises/steamroller.rs: -------------------------------------------------------------------------------- 1 | // Flatten a nested array. You must account for varying levels of nesting. 2 | 3 | #[allow(dead_code)] 4 | #[allow(unused_variables)] 5 | enum Value { 6 | Number(i32), 7 | Array(Vec), 8 | } 9 | 10 | #[allow(dead_code)] 11 | #[allow(unused_variables)] 12 | fn steamroll_array(arr: &[Value]) -> Vec { 13 | unimplemented!() 14 | } 15 | 16 | #[cfg(test)] 17 | mod tests { 18 | use super::*; 19 | 20 | #[test] 21 | fn test1() { 22 | let arr = [ 23 | Value::Number(1), 24 | Value::Array(vec![Value::Number(2)]), 25 | Value::Array(vec![ 26 | Value::Number(3), 27 | Value::Array(vec![Value::Array(vec![Value::Number(4)])]), 28 | ]), 29 | ]; 30 | 31 | assert_eq!(steamroll_array(&arr), vec![1, 2, 3, 4]); 32 | } 33 | 34 | #[test] 35 | fn test2() { 36 | let arr = [ 37 | Value::Number(1), 38 | Value::Array(vec![]), 39 | Value::Array(vec![ 40 | Value::Number(3), 41 | Value::Array(vec![Value::Array(vec![Value::Number(4)])]), 42 | ]), 43 | ]; 44 | 45 | assert_eq!(steamroll_array(&arr), vec![1, 3, 4]); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/exercises/sum_all_numbers_in_range.rs: -------------------------------------------------------------------------------- 1 | // We'll pass you an array of two numbers. 2 | // Return the sum of those two numbers plus the sum of all the numbers between them. 3 | // The lowest number will not always come first. 4 | 5 | // For example, sumAll([4,1]) should return 10 because sum of all the numbers between 1 and 4 (both inclusive) is 10. 6 | 7 | #[allow(dead_code)] 8 | #[allow(unused_variables)] 9 | pub fn sum_all(arr: &mut [i32; 2]) -> i32 { 10 | unimplemented!() 11 | } 12 | 13 | #[cfg(test)] 14 | mod tests { 15 | use super::*; 16 | 17 | #[test] 18 | fn test1() { 19 | let mut arg = [1, 4]; 20 | 21 | assert_eq!(sum_all(&mut arg), 10); 22 | } 23 | 24 | #[test] 25 | fn test2() { 26 | let mut arg = [4, 1]; 27 | 28 | assert_eq!(sum_all(&mut arg), 10); 29 | } 30 | 31 | #[test] 32 | fn test3() { 33 | let mut arg = [5, 10]; 34 | 35 | assert_eq!(sum_all(&mut arg), 45); 36 | } 37 | 38 | #[test] 39 | fn test4() { 40 | let mut arg = [10, 5]; 41 | 42 | assert_eq!(sum_all(&mut arg), 45); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/exercises/sum_all_primes.rs: -------------------------------------------------------------------------------- 1 | // A prime number is a whole number greater than 1 with exactly two divisors: 1 and itself. 2 | // For example, 2 is a prime number because it is only divisible by 1 and 2. 3 | // In contrast, 4 is not prime since it is divisible by 1, 2 and 4. 4 | 5 | // Rewrite sumPrimes so it returns the sum of all prime numbers that are less than or equal to num. 6 | 7 | #[allow(dead_code)] 8 | #[allow(unused_variables)] 9 | fn sum_primes(num: i64) -> i64 { 10 | unimplemented!() 11 | } 12 | 13 | #[cfg(test)] 14 | mod tests { 15 | use super::*; 16 | 17 | #[test] 18 | fn test1() { 19 | assert_eq!(sum_primes(10), 17); 20 | } 21 | 22 | #[test] 23 | fn test2() { 24 | assert_eq!(sum_primes(977), 73156); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/exercises/sum_odd_fibonacci_numbers.rs: -------------------------------------------------------------------------------- 1 | // Given a positive integer num, return the sum of all odd Fibonacci numbers that are less than or equal to num. 2 | 3 | // The first two numbers in the Fibonacci sequence are 0 and 1. Every additional number in the sequence is the sum of the two previous numbers. 4 | // The first seven numbers of the Fibonacci sequence are 0, 1, 1, 2, 3, 5 and 8. 5 | 6 | // For example, sumFibs(10) should return 10 because all odd Fibonacci numbers less than or equal to 10 are 1, 1, 3, and 5. 7 | 8 | #[allow(dead_code)] 9 | #[allow(unused_variables)] 10 | fn sum_fibs(num: i64) -> i64 { 11 | unimplemented!() 12 | } 13 | 14 | #[cfg(test)] 15 | mod tests { 16 | use super::*; 17 | 18 | #[test] 19 | fn test1() { 20 | assert_eq!(sum_fibs(1000), 1785); 21 | } 22 | 23 | #[test] 24 | fn test2() { 25 | assert_eq!(sum_fibs(4000000), 4613732); 26 | } 27 | 28 | #[test] 29 | fn test3() { 30 | assert_eq!(sum_fibs(4), 5); 31 | } 32 | 33 | #[test] 34 | fn test4() { 35 | assert_eq!(sum_fibs(75024), 60696); 36 | } 37 | 38 | #[test] 39 | fn test5() { 40 | assert_eq!(sum_fibs(75025), 135721); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/exercises/wherefore_art_thou.rs: -------------------------------------------------------------------------------- 1 | // Make a function that looks through an array of objects (first argument) and returns an array of all objects 2 | // that have matching name and value pairs (second argument). 3 | // Each name and value pair of the source object has to be present in the object 4 | // from the collection if it is to be included in the returned array. 5 | 6 | // For example, if the first argument is 7 | // [{ first: "Romeo", last: "Montague" }, { first: "Mercutio", last: null }, { first: "Tybalt", last: "Capulet" }], 8 | // and the second argument is { last: "Capulet" }, then you must return the third object from the array (the first argument), 9 | // because it contains the name and its value, that was passed on as the second argument. 10 | 11 | use std::collections::HashMap; 12 | 13 | #[allow(dead_code)] 14 | #[allow(unused_variables)] 15 | fn what_is_in_a_name( 16 | collection: Vec>, 17 | source: HashMap, 18 | ) -> Vec> { 19 | unimplemented!() 20 | } 21 | 22 | #[cfg(test)] 23 | mod tests { 24 | use super::*; 25 | 26 | #[test] 27 | fn test1() { 28 | let collection = vec![ 29 | HashMap::from([ 30 | ("first".to_string(), "Romeo".to_string()), 31 | ("last".to_string(), "Montague".to_string()), 32 | ]), 33 | HashMap::from([ 34 | ("first".to_string(), "Mercutio".to_string()), 35 | ("last".to_string(), "null".to_string()), 36 | ]), 37 | HashMap::from([ 38 | ("first".to_string(), "Tybalt".to_string()), 39 | ("last".to_string(), "Capulet".to_string()), 40 | ]), 41 | ]; 42 | let query = HashMap::from([("last".to_string(), "Capulet".to_string())]); 43 | 44 | let result = vec![HashMap::from([ 45 | ("first".to_string(), "Tybalt".to_string()), 46 | ("last".to_string(), "Capulet".to_string()), 47 | ])]; 48 | 49 | assert_eq!(what_is_in_a_name(collection, query), result); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | use cli_table::{format::Justify, print_stdout, Cell, Style, Table}; 2 | use colored::*; 3 | use std::io::{self, Write}; 4 | use std::{collections::BTreeMap, error::Error, process::Command}; 5 | 6 | pub mod exercises; 7 | 8 | fn main() -> Result<(), Box> { 9 | let exercises = BTreeMap::from([ 10 | (1, "sum_all_numbers_in_range"), 11 | (2, "diff_two_arrays"), 12 | (3, "seek_and_destroy"), 13 | (4, "wherefore_art_thou"), 14 | (5, "spinal_tab_case"), 15 | (6, "pig_latin"), 16 | (7, "search_and_replace"), 17 | (8, "dna_pairing"), 18 | (9, "missing_letters"), 19 | (10, "sorted_union"), 20 | (11, "convert_html_entities"), 21 | (12, "sum_odd_fibonacci_numbers"), 22 | (13, "sum_all_primes"), 23 | (14, "smallest_common_multiple"), 24 | (15, "drop_it"), 25 | (16, "steamroller"), 26 | (17, "binary_agents"), 27 | (18, "everything_be_true"), 28 | (19, "arguments_optional"), 29 | (20, "make_a_person"), 30 | (21, "map_the_debris"), 31 | ]); 32 | 33 | println!( 34 | "{}\n{}\n{}", 35 | "=========================================================" 36 | .bold() 37 | .yellow(), 38 | "WELCOME TO THE RUST ALGORITHMS AND DATA STRUCTURES COURSE" 39 | .bold() 40 | .yellow(), 41 | "=========================================================" 42 | .bold() 43 | .yellow(), 44 | ); 45 | 46 | let mut table = vec![]; 47 | 48 | for (k, v) in &exercises { 49 | table.push(vec![k.cell().justify(Justify::Right), v.cell()]); 50 | } 51 | 52 | print_stdout( 53 | table 54 | .table() 55 | .title(vec!["No".cell().bold(true), "Exercise".cell().bold(true)]) 56 | .bold(true), 57 | )?; 58 | 59 | loop { 60 | let mut exc = String::new(); 61 | 62 | print!( 63 | "===> {} ({}): ", 64 | "Enter number of exercise".bold(), 65 | "To quit type 0".yellow() 66 | ); 67 | io::stdout().flush()?; 68 | io::stdin().read_line(&mut exc)?; 69 | 70 | if exc.trim() == "all".to_string() { 71 | let output = Command::new("cargo").arg("test").output()?; 72 | 73 | io::stdout().write_all(&output.stdout)?; 74 | } 75 | 76 | let exc = match exc.trim().parse() { 77 | Ok(e) => { 78 | if e >= 0 && e <= exercises.len() as i32 { 79 | e 80 | } else { 81 | -1 82 | } 83 | } 84 | Err(_) => -1, 85 | }; 86 | 87 | if exc == 0 { 88 | break; 89 | } else if exc == -1 { 90 | println!( 91 | "{}", 92 | "Please enter the number of the exercise (1 - 21)" 93 | .bold() 94 | .red() 95 | ); 96 | continue; 97 | } 98 | 99 | let output = Command::new("cargo") 100 | .arg("test") 101 | .arg("--") 102 | .arg(exercises.get(&exc).expect("Exercise not found")) 103 | .output()?; 104 | 105 | io::stdout().write_all(&output.stdout)?; 106 | //io::stderr().write_all(&output.stderr)?; 107 | } 108 | 109 | Ok(()) 110 | } 111 | -------------------------------------------------------------------------------- /src/solutions/arguments_optional.rs: -------------------------------------------------------------------------------- 1 | // Create a function that sums two arguments together. If only one argument is provided, 2 | // then return a function that expects one argument and returns the sum. 3 | // 4 | // For example, addTogether(2, 3) should return 5, and addTogether(2) should return a function. 5 | // 6 | // Calling this returned function with a single argument will then return the sum: 7 | // 8 | // var sumTwoAnd = addTogether(2); 9 | // 10 | // sumTwoAnd(3) returns 5. 11 | // 12 | // If either argument isn't a valid number, return undefined. 13 | 14 | #[allow(dead_code)] 15 | fn curry(a: i32) -> impl Fn(i32) -> i32 { 16 | move |x| a + x 17 | } 18 | 19 | #[allow(dead_code)] 20 | fn add_two(a: i32, b: i32) -> i32 { 21 | a + b 22 | } 23 | 24 | #[cfg(test)] 25 | mod tests { 26 | use super::*; 27 | 28 | #[test] 29 | fn test1() { 30 | assert_eq!(add_two(2, 3), 5); 31 | } 32 | 33 | #[test] 34 | fn test2() { 35 | assert_eq!(add_two(23, 30), 53); 36 | } 37 | 38 | #[test] 39 | fn test3() { 40 | let add_five = curry(5); 41 | 42 | assert_eq!(add_five(7), 12); 43 | } 44 | 45 | #[test] 46 | fn test4() { 47 | let add_twentyfive = curry(25); 48 | 49 | assert_eq!(add_twentyfive(50), 75); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/solutions/binary_agents.rs: -------------------------------------------------------------------------------- 1 | // Return an English translated sentence of the passed binary string. 2 | 3 | // The binary string will be space separated. 4 | 5 | #[allow(dead_code)] 6 | fn binary_agent(s: &str) -> String { 7 | let mut result = String::new(); 8 | 9 | // Splitting string of binary digits into a vector where each element holds one byte, then 10 | // mapping over each byte and converting from base 2 to u8 11 | for byte in s.split(' ').map(|x| u8::from_str_radix(x, 2).unwrap()) { 12 | // Typecasting the u8 value in byte to char (ASCII) and pushing it to the result string 13 | // which will hold the sentence in readable ASCII format 14 | result.push(byte as char); 15 | } 16 | result 17 | } 18 | 19 | #[cfg(test)] 20 | mod tests { 21 | use super::*; 22 | 23 | #[test] 24 | fn test1() { 25 | assert_eq!(binary_agent("01000001 01110010 01100101 01101110 00100111 01110100 00100000 01100010 01101111 01101110 01100110 01101001 01110010 01100101 01110011 00100000 01100110 01110101 01101110 00100001 00111111"), "Aren't bonfires fun!?"); 26 | } 27 | 28 | #[test] 29 | fn test2() { 30 | assert_eq!(binary_agent("01001001 00100000 01101100 01101111 01110110 01100101 00100000 01000110 01110010 01100101 01100101 01000011 01101111 01100100 01100101 01000011 01100001 01101101 01110000 00100001"), "I love FreeCodeCamp!"); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/solutions/convert_html_entities.rs: -------------------------------------------------------------------------------- 1 | // Convert the characters &, <, >, " (double quote), and ' (apostrophe), 2 | // in a string to their corresponding HTML entities. 3 | 4 | // Some characters and their corresponding HTML entities 5 | const ENTITIES: [(&str, &str); 5] = [ 6 | ("&", "&"), 7 | ("<", "<"), 8 | (">", ">"), 9 | ("\"", """), 10 | ("'", "'"), 11 | ]; 12 | 13 | #[allow(dead_code)] 14 | fn convert_html(s: &str) -> String { 15 | let mut result = String::from(s); 16 | 17 | // Iterating over the array of tuples containing character, entity pairs 18 | for (c, e) in ENTITIES { 19 | // Replacing characters with their corresponding HTML entities 20 | result = result.replace(c, e); 21 | } 22 | result 23 | } 24 | 25 | #[cfg(test)] 26 | mod tests { 27 | use super::*; 28 | 29 | #[test] 30 | fn test1() { 31 | assert_eq!(convert_html("Dolce & Gabbana"), "Dolce & Gabbana"); 32 | } 33 | 34 | #[test] 35 | fn test2() { 36 | assert_eq!( 37 | convert_html("Hamburgers < Pizza < Tacos"), 38 | "Hamburgers < Pizza < Tacos" 39 | ); 40 | } 41 | 42 | #[test] 43 | fn test3() { 44 | assert_eq!(convert_html("Sixty > twelve"), "Sixty > twelve"); 45 | } 46 | 47 | #[test] 48 | fn test4() { 49 | assert_eq!( 50 | convert_html("Stuff in \"quotation marks\""), 51 | "Stuff in "quotation marks"" 52 | ); 53 | } 54 | 55 | #[test] 56 | fn test5() { 57 | assert_eq!(convert_html("Schindler's List"), "Schindler's List"); 58 | } 59 | 60 | #[test] 61 | fn test6() { 62 | assert_eq!(convert_html("<>"), "<>"); 63 | } 64 | 65 | #[test] 66 | fn test7() { 67 | assert_eq!(convert_html("abc"), "abc"); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/solutions/diff_two_arrays.rs: -------------------------------------------------------------------------------- 1 | // Compare two arrays and return a new array with any items only found in one of the two given arrays, 2 | // but not both. In other words, return the symmetric difference of the two arrays. 3 | 4 | // Note: You can return the array with its elements in any order. 5 | 6 | #[allow(dead_code)] 7 | fn diff_array<'a>(arr1: Vec<&'a str>, arr2: Vec<&'a str>) -> Vec<&'a str> { 8 | // Check if arr1 contains strings of arr2, if it does delete the string, else push it 9 | for string in arr2 { 10 | if arr1.contains(&string) { 11 | // Find out index of the given string 12 | let index = arr1.iter().position(|&x| x == string).unwrap(); 13 | 14 | // Remove the string at the given index 15 | arr1.remove(index); 16 | } else { 17 | // Else we push the string to arr1 18 | arr1.push(string); 19 | } 20 | } 21 | 22 | // Sorting alphabetically 23 | arr1.sort_by(|a, b| a.to_lowercase().cmp(&b.to_lowercase())); 24 | 25 | arr1 26 | } 27 | 28 | #[cfg(test)] 29 | mod tests { 30 | use super::*; 31 | 32 | #[test] 33 | fn test1() { 34 | let arr1 = vec![ 35 | "diorite", 36 | "andesite", 37 | "grass", 38 | "dirt", 39 | "pink wool", 40 | "dead shrub", 41 | ]; 42 | let arr2 = vec!["diorite", "andesite", "grass", "dirt", "dead shrub"]; 43 | 44 | assert_eq!(diff_array(arr1, arr2), ["pink wool"]); 45 | } 46 | 47 | #[test] 48 | fn test2() { 49 | let arr1 = vec!["andesite", "grass", "dirt", "pink wool", "dead shrub"]; 50 | let arr2 = vec!["diorite", "andesite", "grass", "dirt", "dead shrub"]; 51 | 52 | assert_eq!(diff_array(arr1, arr2), ["diorite", "pink wool"]); 53 | } 54 | 55 | #[test] 56 | fn test3() { 57 | let arr1 = vec!["andesite", "grass", "dirt", "dead shrub"]; 58 | let arr2 = vec!["andesite", "grass", "dirt", "dead shrub"]; 59 | 60 | assert_eq!(diff_array(arr1, arr2).len(), 0); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/solutions/dna_pairing.rs: -------------------------------------------------------------------------------- 1 | // Pairs of DNA strands consist of nucleobase pairs. Base pairs are represented by the characters AT and CG, 2 | // which form building blocks of the DNA double helix. 3 | 4 | // The DNA strand is missing the pairing element. Write a function to match the missing base pairs for the provided DNA strand. 5 | // For each character in the provided string, find the base pair character. Return the results as a 2d array. 6 | 7 | // For example, for the input GCG, return [["G", "C"], ["C","G"], ["G", "C"]] 8 | 9 | // The character and its pair are paired up in an array, and all the arrays are grouped into one encapsulating array. 10 | 11 | #[allow(dead_code)] 12 | fn pair_element(s: &str) -> Vec<[char; 2]> { 13 | // Vector for pairs which will be returned 14 | let mut pairs = Vec::new(); 15 | 16 | // Iterating over characters in string "s" 17 | for c in s.chars() { 18 | pairs.push(match_base_pair(c)); 19 | } 20 | pairs 21 | } 22 | 23 | // Function to return an array of 2 chars with the matching base DNA pair 24 | fn match_base_pair(c: char) -> [char; 2] { 25 | match c { 26 | 'A' => ['A', 'T'], 27 | 'T' => ['T', 'A'], 28 | 'C' => ['C', 'G'], 29 | 'G' => ['G', 'C'], 30 | _ => panic!("Invalid DNA character: {c}"), 31 | } 32 | } 33 | 34 | #[cfg(test)] 35 | mod tests { 36 | use super::*; 37 | 38 | #[test] 39 | fn test1() { 40 | assert_eq!( 41 | pair_element("ATCGA"), 42 | vec![['A', 'T'], ['T', 'A'], ['C', 'G'], ['G', 'C'], ['A', 'T']] 43 | ); 44 | } 45 | 46 | #[test] 47 | fn test2() { 48 | assert_eq!( 49 | pair_element("TTGAG"), 50 | vec![['T', 'A'], ['T', 'A'], ['G', 'C'], ['A', 'T'], ['G', 'C']], 51 | ) 52 | } 53 | 54 | #[test] 55 | fn test3() { 56 | assert_eq!( 57 | pair_element("CTCTA"), 58 | vec![['C', 'G'], ['T', 'A'], ['C', 'G'], ['T', 'A'], ['A', 'T']], 59 | ) 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/solutions/drop_it.rs: -------------------------------------------------------------------------------- 1 | // Given the array arr, iterate through and remove each element starting from the first element (the 0 index) 2 | // until the function func returns true when the iterated element is passed through it. 3 | 4 | // Then return the rest of the array once the condition is satisfied, 5 | // otherwise, arr should be returned as an empty array. 6 | 7 | #[allow(dead_code)] 8 | fn drop_elements(arr: &mut Vec, filter: F) -> Vec 9 | where 10 | F: Fn(&i32) -> bool, 11 | { 12 | for (i, value) in arr.iter().enumerate() { 13 | if filter(value) { 14 | return arr[i..].to_vec(); 15 | } 16 | } 17 | vec![] 18 | } 19 | 20 | #[cfg(test)] 21 | mod tests { 22 | use super::*; 23 | 24 | #[test] 25 | fn test1() { 26 | assert_eq!( 27 | drop_elements(&mut vec![1, 2, 3, 4], |&n| n >= 3), 28 | vec![3, 4] 29 | ); 30 | } 31 | 32 | #[test] 33 | fn test2() { 34 | assert_eq!( 35 | drop_elements(&mut vec![0, 1, 0, 1], |&n| n == 1), 36 | vec![1, 0, 1] 37 | ); 38 | } 39 | 40 | #[test] 41 | fn test3() { 42 | assert_eq!(drop_elements(&mut vec![1, 2, 3], |&n| n > 0), vec![1, 2, 3]); 43 | } 44 | 45 | #[test] 46 | fn test4() { 47 | assert_eq!(drop_elements(&mut vec![1, 2, 3, 4], |&n| n > 5), vec![]); 48 | } 49 | 50 | #[test] 51 | fn test5() { 52 | assert_eq!( 53 | drop_elements(&mut vec![1, 2, 3, 7, 4], |&n| n > 3), 54 | vec![7, 4] 55 | ); 56 | } 57 | 58 | #[test] 59 | fn test6() { 60 | assert_eq!( 61 | drop_elements(&mut vec![1, 2, 3, 9, 2], |&n| n > 2), 62 | vec![3, 9, 2] 63 | ); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/solutions/everything_be_true.rs: -------------------------------------------------------------------------------- 1 | // Check if the predicate (second argument) is truthy on all elements of a collection (first argument). 2 | 3 | // In other words, you are given an array collection of objects. 4 | // The predicate pre will be an object property and you need to return true if its value is truthy. Otherwise, return false. 5 | 6 | // In JavaScript, truthy values are values that translate to true when evaluated in a Boolean context. 7 | 8 | // Remember, you can access object properties through either dot notation or [] notation. 9 | 10 | // Enum to hold Person or Pokemon type so both types can be passed as argument for truth_check() 11 | #[derive(PartialEq)] 12 | #[allow(dead_code)] 13 | enum Type { 14 | Person(Person), 15 | Pokemon(Pokemon), 16 | } 17 | 18 | // Methods returning value of certain field 19 | impl Type { 20 | fn name(&self) -> &str { 21 | match self { 22 | Type::Person(pers) => &pers.name, 23 | _ => panic!("Not valid type"), 24 | } 25 | } 26 | 27 | fn role(&self) -> &str { 28 | match self { 29 | Type::Person(pers) => &pers.role, 30 | _ => panic!("Not a valid type"), 31 | } 32 | } 33 | 34 | fn is_bot(&self) -> bool { 35 | match self { 36 | Type::Person(pers) => pers.is_bot, 37 | _ => panic!("Not a valid type"), 38 | } 39 | } 40 | 41 | fn number(&self) -> i32 { 42 | match self { 43 | Type::Pokemon(pkmn) => pkmn.number, 44 | _ => panic!("Not a valid type"), 45 | } 46 | } 47 | 48 | fn caught(&self) -> i32 { 49 | match self { 50 | Type::Pokemon(pkmn) => pkmn.caught, 51 | _ => panic!("Not a valid type"), 52 | } 53 | } 54 | } 55 | 56 | #[derive(PartialEq)] 57 | struct Person { 58 | name: String, 59 | role: String, 60 | is_bot: bool, 61 | } 62 | 63 | #[derive(PartialEq)] 64 | struct Pokemon { 65 | name: String, 66 | number: i32, 67 | caught: i32, 68 | } 69 | 70 | #[allow(dead_code)] 71 | fn truth_check(collection: Vec, pre: &str) -> bool { 72 | // Itering over vector of elements either of Person or Pokemon type and emulating JavaScript 73 | // falsy values to check if everything is truthy (values that are true in a Boolean context) 74 | collection.iter().all(|p| match pre { 75 | "name" => p.name() != "", 76 | "role" => p.role() != "", 77 | "is_bot" => p.is_bot() != false, 78 | "number" => p.number() != 0, 79 | "caught" => p.caught() != 0, 80 | _ => panic!("No field name found for {pre}"), 81 | }) 82 | } 83 | 84 | #[cfg(test)] 85 | mod tests { 86 | use super::*; 87 | 88 | #[test] 89 | fn test1() { 90 | let p1: Person = Person { 91 | name: String::from("Quincy"), 92 | role: String::from("Founder"), 93 | is_bot: false, 94 | }; 95 | 96 | let p2: Person = Person { 97 | name: String::from("Naomi"), 98 | role: String::from(""), 99 | is_bot: false, 100 | }; 101 | 102 | let p3: Person = Person { 103 | name: String::from("Camperbot"), 104 | role: String::from("Bot"), 105 | is_bot: true, 106 | }; 107 | 108 | let collection = vec![Type::Person(p1), Type::Person(p2), Type::Person(p3)]; 109 | 110 | assert_eq!(truth_check(collection, "is_bot"), false); 111 | } 112 | 113 | #[test] 114 | fn test2() { 115 | let p1: Person = Person { 116 | name: String::from("Quincy"), 117 | role: String::from("Founder"), 118 | is_bot: false, 119 | }; 120 | 121 | let p2: Person = Person { 122 | name: String::from("Naomi"), 123 | role: String::from(""), 124 | is_bot: false, 125 | }; 126 | 127 | let p3: Person = Person { 128 | name: String::from("Camperbot"), 129 | role: String::from("Bot"), 130 | is_bot: true, 131 | }; 132 | 133 | let collection = vec![Type::Person(p1), Type::Person(p2), Type::Person(p3)]; 134 | 135 | assert_eq!(truth_check(collection, "name"), true); 136 | } 137 | 138 | #[test] 139 | fn test3() { 140 | let p1: Person = Person { 141 | name: String::from("Quincy"), 142 | role: String::from("Founder"), 143 | is_bot: false, 144 | }; 145 | 146 | let p2: Person = Person { 147 | name: String::from("Naomi"), 148 | role: String::from(""), 149 | is_bot: false, 150 | }; 151 | 152 | let p3: Person = Person { 153 | name: String::from("Camperbot"), 154 | role: String::from("Bot"), 155 | is_bot: true, 156 | }; 157 | 158 | let collection = vec![Type::Person(p1), Type::Person(p2), Type::Person(p3)]; 159 | 160 | assert_eq!(truth_check(collection, "role"), false); 161 | } 162 | 163 | #[test] 164 | fn test4() { 165 | let pkmn1: Pokemon = Pokemon { 166 | name: String::from("Pikachu"), 167 | number: 25, 168 | caught: 3, 169 | }; 170 | 171 | let pkmn2: Pokemon = Pokemon { 172 | name: String::from("Togepi"), 173 | number: 175, 174 | caught: 1, 175 | }; 176 | 177 | let collection = vec![Type::Pokemon(pkmn1), Type::Pokemon(pkmn2)]; 178 | 179 | assert_eq!(truth_check(collection, "number"), true); 180 | } 181 | } 182 | -------------------------------------------------------------------------------- /src/solutions/make_a_person.rs: -------------------------------------------------------------------------------- 1 | // Fill in the object constructor with the following methods below: 2 | // 3 | // getFirstName() 4 | // getLastName() 5 | // getFullName() 6 | // setFirstName(first) 7 | // setLastName(last) 8 | // setFullName(firstAndLast) 9 | // 10 | // Run the tests to see the expected output for each method. 11 | // The methods that take an argument must accept only one argument and it has to be a string. 12 | // These methods must be the only available means of interacting with the object. 13 | 14 | #[allow(dead_code)] 15 | struct Person { 16 | first_name: String, 17 | last_name: String, 18 | } 19 | 20 | #[allow(dead_code)] 21 | impl Person { 22 | fn create(first_name: &str, last_name: &str) -> Self { 23 | Person { 24 | first_name: first_name.to_string(), 25 | last_name: last_name.to_string(), 26 | } 27 | } 28 | 29 | fn get_first_name(&self) -> &str { 30 | &self.first_name 31 | } 32 | 33 | fn get_last_name(&self) -> &str { 34 | &self.last_name 35 | } 36 | 37 | fn get_full_name(&self) -> String { 38 | format!("{} {}", &self.first_name, &self.last_name) 39 | } 40 | 41 | fn set_first_name(&mut self, first_name: &str) { 42 | self.first_name = first_name.to_string(); 43 | } 44 | 45 | fn set_last_name(&mut self, last_name: &str) { 46 | self.last_name = last_name.to_string(); 47 | } 48 | 49 | fn set_full_name(&mut self, first_name: &str, last_name: &str) { 50 | self.first_name = first_name.to_string(); 51 | self.last_name = last_name.to_string(); 52 | } 53 | } 54 | 55 | #[cfg(test)] 56 | mod tests { 57 | use super::*; 58 | 59 | #[test] 60 | fn test1() { 61 | let bob = Person::create("Bob", "Ross"); 62 | 63 | assert_eq!(bob.get_first_name(), "Bob"); 64 | } 65 | 66 | #[test] 67 | fn test2() { 68 | let bob = Person::create("Bob", "Ross"); 69 | 70 | assert_eq!(bob.get_last_name(), "Ross"); 71 | } 72 | 73 | #[test] 74 | fn test3() { 75 | let bob = Person::create("Bob", "Ross"); 76 | 77 | assert_eq!(bob.get_full_name(), "Bob Ross".to_string()); 78 | } 79 | 80 | #[test] 81 | fn test4() { 82 | let mut bob = Person::create("Bob", "Ross"); 83 | 84 | bob.set_first_name("Haskell"); 85 | 86 | assert_eq!(bob.get_full_name(), "Haskell Ross".to_string()); 87 | } 88 | 89 | #[test] 90 | fn test5() { 91 | let mut bob = Person::create("Bob", "Ross"); 92 | 93 | bob.set_first_name("Haskell"); 94 | bob.set_last_name("Curry"); 95 | 96 | assert_eq!(bob.get_full_name(), "Haskell Curry".to_string()); 97 | } 98 | 99 | #[test] 100 | fn test6() { 101 | let mut bob = Person::create("Bob", "Ross"); 102 | 103 | bob.set_full_name("Haskell", "Curry"); 104 | 105 | assert_eq!(bob.get_full_name(), "Haskell Curry".to_string()); 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/solutions/map_the_debris.rs: -------------------------------------------------------------------------------- 1 | // According to Kepler's Third Law, the orbital period T of two point masses orbiting 2 | // each other in a circular or elliptic orbit is: 3 | // 4 | // T=2π√a^3/μ 5 | // 6 | // - a is the orbit's semi-major axis 7 | // - μ=GM is the standard gravitational parameter 8 | // - G is the gravitational constant, 9 | // - M is the mass of the more massive body. 10 | // 11 | // Return a new array that transforms the elements' average altitude into their orbital periods (in seconds). 12 | 13 | // The array will contain objects in the format {name: 'name', avgAlt: avgAlt}. 14 | // 15 | // The values should be rounded to the nearest whole number. The body being orbited is Earth. 16 | // 17 | // The radius of the earth is 6367.4447 kilometers, and the GM value of earth is 398600.4418 km^3s^-2. 18 | 19 | use std::f64::consts::PI; 20 | 21 | #[allow(dead_code)] 22 | #[derive(Debug, PartialEq)] 23 | struct Satellite { 24 | name: String, 25 | avg_alt: f64, 26 | } 27 | 28 | #[allow(dead_code)] 29 | fn orbital_period(arr: Vec) -> Vec<(String, i32)> { 30 | // Setting given constonants in the exercise 31 | const GM: f64 = 398600.4418; 32 | const EARTH_RADIUS: f64 = 6367.4447; 33 | 34 | // Iter over the vector of struct Satellite 35 | arr.iter() 36 | .map(|sat| { 37 | let earth = EARTH_RADIUS + sat.avg_alt; 38 | // Applying mathematical formula from above 39 | let orbital_period = (2.0 * PI * (earth.powi(3) / GM).sqrt()).round() as i32; 40 | 41 | // Returning a tuple of the name and orbital period of the given satellite 42 | (sat.name.clone(), orbital_period) 43 | }) 44 | .collect() 45 | } 46 | 47 | #[cfg(test)] 48 | mod tests { 49 | use super::*; 50 | 51 | #[test] 52 | fn test1() { 53 | let sputnik = Satellite { 54 | name: "sputnik".to_string(), 55 | avg_alt: 35873.5553, 56 | }; 57 | 58 | assert_eq!( 59 | orbital_period(vec![sputnik]), 60 | vec![("sputnik".to_string(), 86400)] 61 | ); 62 | } 63 | 64 | #[test] 65 | fn test2() { 66 | let iss = Satellite { 67 | name: "iss".to_string(), 68 | avg_alt: 413.6, 69 | }; 70 | let hubble = Satellite { 71 | name: "hubble".to_string(), 72 | avg_alt: 556.7, 73 | }; 74 | let moon = Satellite { 75 | name: "moon".to_string(), 76 | avg_alt: 378632.553, 77 | }; 78 | 79 | let result = vec![ 80 | ("iss".to_string(), 5557), 81 | ("hubble".to_string(), 5734), 82 | ("moon".to_string(), 2377399), 83 | ]; 84 | 85 | assert_eq!(orbital_period(vec![iss, hubble, moon]), result) 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/solutions/missing_letters.rs: -------------------------------------------------------------------------------- 1 | // Find the missing letter in the passed letter range and return it. 2 | 3 | // If all letters are present in the range, return undefined. 4 | 5 | #[allow(dead_code)] 6 | fn fear_not_letter(s: &str) -> Option { 7 | // Using the chars() method to iterate over the next char and typecasting then into u8, the 8 | // next() method returns "None" if "s" is empty 9 | let mut curr_char_code = s.chars().next()? as u8; 10 | let mut missing = None; 11 | 12 | // Iterating over the characters in string "s" 13 | for c in s.chars() { 14 | // If the character in "s" is equal to the current character code then we increment the 15 | // ASCII value of curr_char_code by one to go one letter further and then check again 16 | if c as u8 == curr_char_code { 17 | curr_char_code += 1; 18 | } 19 | // Else we found the missing character and store it in the variable "missing" which we 20 | // then return 21 | else { 22 | missing = Some(curr_char_code as char); 23 | break; 24 | } 25 | } 26 | missing 27 | } 28 | 29 | #[cfg(test)] 30 | mod tests { 31 | use super::*; 32 | 33 | #[test] 34 | fn test1() { 35 | assert_eq!(fear_not_letter("abce"), Some('d')); 36 | } 37 | 38 | #[test] 39 | fn test2() { 40 | assert_eq!(fear_not_letter("abcdefghjklmno"), Some('i')); 41 | } 42 | 43 | #[test] 44 | fn test3() { 45 | assert_eq!(fear_not_letter("stvwx"), Some('u')); 46 | } 47 | 48 | #[test] 49 | fn test4() { 50 | assert_eq!(fear_not_letter("bcdf"), Some('e')); 51 | } 52 | 53 | #[test] 54 | fn test5() { 55 | assert_eq!(fear_not_letter("abcdefghijklmnopqrstuvwxyz"), None); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/solutions/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod arguments_optional; 2 | pub mod binary_agents; 3 | pub mod convert_html_entities; 4 | pub mod diff_two_arrays; 5 | pub mod dna_pairing; 6 | pub mod drop_it; 7 | pub mod everything_be_true; 8 | pub mod make_a_person; 9 | pub mod map_the_debris; 10 | pub mod missing_letters; 11 | pub mod pig_latin; 12 | pub mod search_and_replace; 13 | pub mod seek_and_destroy; 14 | pub mod smallest_common_multiple; 15 | pub mod sorted_union; 16 | pub mod spinal_tab_case; 17 | pub mod steamroller; 18 | pub mod sum_all_numbers_in_range; 19 | pub mod sum_all_primes; 20 | pub mod sum_odd_fibonacci_numbers; 21 | pub mod wherefore_art_thou; 22 | -------------------------------------------------------------------------------- /src/solutions/pig_latin.rs: -------------------------------------------------------------------------------- 1 | // Pig Latin is a way of altering English Words. The rules are as follows: 2 | 3 | // - If a word begins with a consonant, take the first consonant or consonant cluster, 4 | // move it to the end of the word, and add ay to it. 5 | 6 | // - If a word begins with a vowel, just add way at the end. 7 | 8 | // Translate the provided string to Pig Latin. Input strings are guaranteed to be English words in all lowercase. 9 | 10 | use regex::Regex; 11 | 12 | #[allow(dead_code)] 13 | fn translate_pig_latin(s: String) -> String { 14 | // Regex to check if s starts with a vowel 15 | let re = Regex::new(r"^[aeiou]+").unwrap(); 16 | let mut result = String::new(); 17 | 18 | // If s starts with vowel, push to result string and add "way" at the end 19 | if re.is_match(&s) { 20 | result.push_str(&s); 21 | result.push_str("way"); 22 | } else { 23 | // If starting with consonant(s) then taking the consonant(s) and putting them at the end, 24 | // then adding "ay" 25 | let re = Regex::new(r"(^[^aeiou]+)(\w*)").unwrap(); 26 | 27 | result = re.replace(&s, "${2}${1}ay").to_string(); 28 | } 29 | result 30 | } 31 | 32 | #[cfg(test)] 33 | mod tests { 34 | use super::*; 35 | 36 | #[test] 37 | fn test1() { 38 | assert_eq!( 39 | translate_pig_latin("california".to_string()), 40 | "aliforniacay" 41 | ); 42 | } 43 | 44 | #[test] 45 | fn test2() { 46 | assert_eq!( 47 | translate_pig_latin("paragraphs".to_string()), 48 | "aragraphspay" 49 | ); 50 | } 51 | 52 | #[test] 53 | fn test3() { 54 | assert_eq!(translate_pig_latin("glove".to_string()), "oveglay"); 55 | } 56 | 57 | #[test] 58 | fn test4() { 59 | assert_eq!(translate_pig_latin("algorithm".to_string()), "algorithmway"); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/solutions/search_and_replace.rs: -------------------------------------------------------------------------------- 1 | // Perform a search and replace on the sentence using the arguments provided and return the new sentence. 2 | 3 | // First argument is the sentence to perform the search and replace on. 4 | 5 | // Second argument is the word that you will be replacing (before). 6 | 7 | // Third argument is what you will be replacing the second argument with (after). 8 | 9 | // Note: Preserve the case of the first character in the original word when you are replacing it. 10 | // For example if you mean to replace the word Book with the word dog, it should be replaced as Dog 11 | 12 | use regex::Regex; 13 | 14 | #[allow(dead_code)] 15 | fn my_replace(s: &str, before: &str, after: &str) -> String { 16 | // Regex to check if first letter of "before" is capital 17 | let re = Regex::new(r"^[A-Z]").unwrap(); 18 | 19 | // Converting after from &str to String and making it mutable 20 | let mut after = after.to_string(); 21 | 22 | // If it is capital then capitalize first letter of after too 23 | if re.is_match(before) { 24 | after = first_to_upper(&after); 25 | } 26 | // Else if the "before" is lowercase and "after" is uppercase just make "after" lowercase too 27 | else if !re.is_match(before) && re.is_match(&after) { 28 | after = after.to_lowercase(); 29 | } 30 | // Replacing "before" with "after" and returning the String 31 | s.replace(before, &after) 32 | } 33 | 34 | // Function to capitalize the first letter of a string 35 | fn first_to_upper(s: &str) -> String { 36 | let mut c = s.chars(); 37 | 38 | match c.next() { 39 | None => String::new(), 40 | Some(f) => f.to_uppercase().collect::() + c.as_str(), 41 | } 42 | } 43 | 44 | #[cfg(test)] 45 | mod tests { 46 | use super::*; 47 | 48 | #[test] 49 | fn test1() { 50 | assert_eq!( 51 | my_replace("Let us go to the store", "store", "mall"), 52 | "Let us go to the mall" 53 | ); 54 | } 55 | 56 | #[test] 57 | fn test2() { 58 | assert_eq!( 59 | my_replace("He is Sleeping on the couch", "Sleeping", "sitting"), 60 | "He is Sitting on the couch" 61 | ); 62 | } 63 | 64 | #[test] 65 | fn test3() { 66 | assert_eq!( 67 | my_replace("I think we should look up there", "up", "Down"), 68 | "I think we should look down there" 69 | ); 70 | } 71 | 72 | #[test] 73 | fn test4() { 74 | assert_eq!( 75 | my_replace("This has a spellngi error", "spellngi", "spelling"), 76 | "This has a spelling error" 77 | ); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/solutions/seek_and_destroy.rs: -------------------------------------------------------------------------------- 1 | // You will be provided with an initial array (the first argument in the destroyer function), 2 | // followed by one or more arguments. Remove all elements from the initial array that are of 3 | // the same value as these arguments. 4 | 5 | // Note: You have to use the arguments object. 6 | 7 | #[allow(dead_code)] 8 | fn destroyer(arr: &mut Vec, args: &[i32]) -> Vec { 9 | // If the integer in the args array is not equal to an element in the arr array then retain 10 | // (keep) it, else it will get removed 11 | for arg in args { 12 | arr.retain(|&x| x != *arg); 13 | } 14 | arr.to_vec() 15 | } 16 | 17 | #[cfg(test)] 18 | mod tests { 19 | use super::*; 20 | 21 | #[test] 22 | fn test1() { 23 | let mut arr = vec![1, 2, 3, 1, 2, 3]; 24 | let args = vec![2, 3]; 25 | 26 | assert_eq!(destroyer(&mut arr, &args), [1, 1]); 27 | } 28 | 29 | #[test] 30 | fn test2() { 31 | let mut arr = vec![1, 2, 3, 5, 1, 2, 3]; 32 | let args = vec![2, 3]; 33 | 34 | assert_eq!(destroyer(&mut arr, &args), [1, 5, 1]); 35 | } 36 | 37 | #[test] 38 | fn test3() { 39 | let mut arr = vec![3, 5, 1, 2, 2]; 40 | let args = vec![2, 3, 5]; 41 | 42 | assert_eq!(destroyer(&mut arr, &args), [1]); 43 | } 44 | 45 | #[test] 46 | fn test4() { 47 | let mut arr = vec![2, 3, 2, 3]; 48 | let args = vec![2, 3]; 49 | 50 | assert_eq!(destroyer(&mut arr, &args).len(), 0); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/solutions/smallest_common_multiple.rs: -------------------------------------------------------------------------------- 1 | // Find the smallest common multiple of the provided parameters that can be evenly divided by both, 2 | // as well as by all sequential numbers in the range between these parameters. 3 | 4 | // The range will be an array of two numbers that will not necessarily be in numerical order. 5 | 6 | // For example, if given 1 and 3, find the smallest common multiple of both 1 and 3 that is also 7 | // evenly divisible by all numbers between 1 and 3. The answer here would be 6. 8 | 9 | #[allow(dead_code)] 10 | fn smallest_commons(mut arr: [i32; 2]) -> i32 { 11 | // Sorting the two numbers so the smaller one is at index 0 and the bigger one at 1 12 | arr.sort(); 13 | 14 | // Destructuring array so the meaning is more clear 15 | let (start, end) = (arr[0], arr[1]); 16 | 17 | // From the range of start to end (e.g. 1 to 5) multiplying each number in the range by the 18 | // accumulator value and dividing the result by the greatest common divisor of the 19 | // accumulator value 20 | let lcm = (start..=end).fold(start, |acc, n| (acc * n) / gcd(acc, n)); 21 | 22 | lcm 23 | } 24 | 25 | // Function to find the greatest common divisor of two ints using recursion 26 | fn gcd(a: i32, b: i32) -> i32 { 27 | match b { 28 | 0 => a, 29 | _ => gcd(b, a % b), 30 | } 31 | } 32 | 33 | #[cfg(test)] 34 | mod tests { 35 | use super::*; 36 | 37 | #[test] 38 | fn test1() { 39 | assert_eq!(smallest_commons([1, 5]), 60); 40 | } 41 | 42 | #[test] 43 | fn test2() { 44 | assert_eq!(smallest_commons([5, 1]), 60); 45 | } 46 | 47 | #[test] 48 | fn test3() { 49 | assert_eq!(smallest_commons([2, 10]), 2520); 50 | } 51 | 52 | #[test] 53 | fn test4() { 54 | assert_eq!(smallest_commons([1, 13]), 360360); 55 | } 56 | 57 | #[test] 58 | fn test5() { 59 | assert_eq!(smallest_commons([23, 18]), 6056820); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/solutions/sorted_union.rs: -------------------------------------------------------------------------------- 1 | // Write a function that takes two or more arrays and returns a new array of unique values in the order of the original provided arrays. 2 | 3 | // In other words, all values present from all arrays should be included in their original order, but with no duplicates in the final array. 4 | 5 | // The unique numbers should be sorted by their original order, but the final array should not be sorted in numerical order. 6 | 7 | // Check the assertion tests for examples. 8 | 9 | #[allow(dead_code)] 10 | fn unite_unique(arr: Vec>) -> Vec { 11 | // Flattening all vectors into a single one 12 | let arr: Vec = arr.into_iter().flatten().collect(); 13 | let mut result = Vec::new(); 14 | 15 | // Iterating over the integers in the flattened vector and checking if the integer already 16 | // exists in the vector we will return, if it does, we won't push the integer into it 17 | for num in arr { 18 | if !result.contains(&num) { 19 | result.push(num); 20 | } 21 | } 22 | result 23 | } 24 | 25 | #[cfg(test)] 26 | mod tests { 27 | use super::*; 28 | 29 | #[test] 30 | fn test1() { 31 | assert_eq!( 32 | unite_unique([vec![1, 3, 2], vec![5, 2, 1, 4], vec![2, 1]].to_vec()), 33 | [1, 3, 2, 5, 4].to_vec() 34 | ); 35 | } 36 | 37 | #[test] 38 | fn test2() { 39 | assert_eq!( 40 | unite_unique([vec![1, 2, 3], vec![5, 2, 1]].to_vec()), 41 | [1, 2, 3, 5].to_vec() 42 | ); 43 | } 44 | 45 | #[test] 46 | fn test3() { 47 | assert_eq!( 48 | unite_unique([vec![1, 2, 3], vec![5, 2, 1, 4], vec![2, 1], vec![6, 7, 8]].to_vec()), 49 | [1, 2, 3, 5, 4, 6, 7, 8].to_vec() 50 | ); 51 | } 52 | 53 | #[test] 54 | fn test4() { 55 | assert_eq!( 56 | unite_unique([vec![1, 3, 2], vec![5, 4], vec![5, 6]].to_vec()), 57 | [1, 3, 2, 5, 4, 6].to_vec() 58 | ); 59 | } 60 | 61 | #[test] 62 | fn test5() { 63 | assert_eq!( 64 | unite_unique([vec![1, 3, 2, 3], vec![5, 2, 1, 4], vec![2, 1]].to_vec()), 65 | [1, 3, 2, 5, 4].to_vec() 66 | ); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/solutions/spinal_tab_case.rs: -------------------------------------------------------------------------------- 1 | // Convert a string to spinal case. Spinal case is all-lowercase-words-joined-by-dashes. 2 | 3 | use regex::Regex; 4 | 5 | #[allow(dead_code)] 6 | fn spinal_case(mut s: String) -> String { 7 | // Regex for checking if the string is in camelCase 8 | let re = Regex::new(r"([a-z])([A-Z])").unwrap(); 9 | 10 | // Splitting up "camelCase" to "camel Case" 11 | s = re.replace_all(&s, "${1} ${2}").to_string(); 12 | 13 | // Regex to define delimiter for split method 14 | let re = Regex::new(r"\s|_").unwrap(); 15 | 16 | // Split string at delimiter (either whitespace or underscore) then collecting them into a 17 | // vector then iterating over it and switching every string in the vector to lowercase, then 18 | // join the vector of strings to a single string with '-' as delimiter 19 | re.split(&s) 20 | .map(|s| s.to_lowercase()) 21 | .collect::>() 22 | .join("-") 23 | } 24 | 25 | #[cfg(test)] 26 | mod tests { 27 | use super::*; 28 | 29 | #[test] 30 | fn test1() { 31 | assert_eq!( 32 | spinal_case("This Is Spinal Tap".to_string()), 33 | "this-is-spinal-tap" 34 | ); 35 | } 36 | 37 | #[test] 38 | fn test2() { 39 | assert_eq!( 40 | spinal_case("thisIsSpinalTap".to_string()), 41 | "this-is-spinal-tap" 42 | ); 43 | } 44 | 45 | #[test] 46 | fn test3() { 47 | assert_eq!( 48 | spinal_case("The_Andy_Griffith_Show".to_string()), 49 | "the-andy-griffith-show" 50 | ); 51 | } 52 | 53 | #[test] 54 | fn test4() { 55 | assert_eq!( 56 | spinal_case("Teletubbies say Eh-oh".to_string()), 57 | "teletubbies-say-eh-oh" 58 | ); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/solutions/steamroller.rs: -------------------------------------------------------------------------------- 1 | // Flatten a nested array. You must account for varying levels of nesting. 2 | 3 | #[allow(dead_code)] 4 | enum Value { 5 | Number(i32), 6 | Array(Vec), 7 | } 8 | 9 | #[allow(dead_code)] 10 | fn steamroll_array(arr: &[Value]) -> Vec { 11 | // Empty vector which holds i32 values 12 | let mut result = Vec::new(); 13 | 14 | // Iterating over each item in array arr 15 | for val in arr { 16 | // Matching type of item val 17 | match val { 18 | // If number (i32 integer) then push to the result vector 19 | Value::Number(n) => result.push(*n), 20 | // If nested vector then recursively call function again with nested vector as 21 | // argument, then extending the result array with the return value of function 22 | // call, which is a flattened vector 23 | Value::Array(sub_arr) => result.extend(steamroll_array(sub_arr)), 24 | } 25 | } 26 | result 27 | } 28 | 29 | #[cfg(test)] 30 | mod tests { 31 | use super::*; 32 | 33 | #[test] 34 | fn test1() { 35 | let arr = [ 36 | Value::Number(1), 37 | Value::Array(vec![Value::Number(2)]), 38 | Value::Array(vec![ 39 | Value::Number(3), 40 | Value::Array(vec![Value::Array(vec![Value::Number(4)])]), 41 | ]), 42 | ]; 43 | 44 | assert_eq!(steamroll_array(&arr), vec![1, 2, 3, 4]); 45 | } 46 | 47 | #[test] 48 | fn test2() { 49 | let arr = [ 50 | Value::Number(1), 51 | Value::Array(vec![]), 52 | Value::Array(vec![ 53 | Value::Number(3), 54 | Value::Array(vec![Value::Array(vec![Value::Number(4)])]), 55 | ]), 56 | ]; 57 | 58 | assert_eq!(steamroll_array(&arr), vec![1, 3, 4]); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/solutions/sum_all_numbers_in_range.rs: -------------------------------------------------------------------------------- 1 | // We'll pass you an array of two numbers. 2 | // Return the sum of those two numbers plus the sum of all the numbers between them. 3 | // The lowest number will not always come first. 4 | 5 | // For example, sumAll([4,1]) should return 10 because sum of all the numbers between 1 and 4 (both inclusive) is 10. 6 | 7 | #[allow(dead_code)] 8 | pub fn sum_all(arr: &mut [i32; 2]) -> i32 { 9 | // Sort array (that's why arr is mutable!) 10 | arr.sort(); 11 | 12 | // Take range from first index of slice to last index and sum all the integers in the sum 13 | // together 14 | (arr[0]..=arr[1]).sum() 15 | } 16 | 17 | #[cfg(test)] 18 | mod tests { 19 | use super::*; 20 | 21 | #[test] 22 | fn test1() { 23 | let mut arg = [1, 4]; 24 | 25 | assert_eq!(sum_all(&mut arg), 10); 26 | } 27 | 28 | #[test] 29 | fn test2() { 30 | let mut arg = [4, 1]; 31 | 32 | assert_eq!(sum_all(&mut arg), 10); 33 | } 34 | 35 | #[test] 36 | fn test3() { 37 | let mut arg = [5, 10]; 38 | 39 | assert_eq!(sum_all(&mut arg), 45); 40 | } 41 | 42 | #[test] 43 | fn test4() { 44 | let mut arg = [10, 5]; 45 | 46 | assert_eq!(sum_all(&mut arg), 45); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/solutions/sum_all_primes.rs: -------------------------------------------------------------------------------- 1 | // A prime number is a whole number greater than 1 with exactly two divisors: 1 and itself. 2 | // For example, 2 is a prime number because it is only divisible by 1 and 2. 3 | // In contrast, 4 is not prime since it is divisible by 1, 2 and 4. 4 | 5 | // Rewrite sumPrimes so it returns the sum of all prime numbers that are less than or equal to num. 6 | 7 | #[allow(dead_code)] 8 | fn sum_primes(num: i64) -> i64 { 9 | // Iterating from 2 (because 1 is not a prime number because it is not dividable by 2 numbers), 10 | // then filtering only the numbers which returned true when passed to the is_prime() function 11 | // and eventually adding them together 12 | (2..=num).filter(|&n| is_prime(n)).sum() 13 | } 14 | 15 | // Function to find out if a number is a prime by checking if the given number (n) is NOT evenly 16 | // dividable by all numbers from 2 to the square root of the given number (n) 17 | fn is_prime(n: i64) -> bool { 18 | (2..=(n as f64).sqrt() as i64).all(|i| n % i != 0) 19 | } 20 | 21 | #[cfg(test)] 22 | mod tests { 23 | use super::*; 24 | 25 | #[test] 26 | fn test1() { 27 | assert_eq!(sum_primes(10), 17); 28 | } 29 | 30 | #[test] 31 | fn test2() { 32 | assert_eq!(sum_primes(977), 73156); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/solutions/sum_odd_fibonacci_numbers.rs: -------------------------------------------------------------------------------- 1 | // Given a positive integer num, return the sum of all odd Fibonacci numbers that are less than or equal to num. 2 | 3 | // The first two numbers in the Fibonacci sequence are 0 and 1. Every additional number in the sequence is the sum of the two previous numbers. 4 | // The first seven numbers of the Fibonacci sequence are 0, 1, 1, 2, 3, 5 and 8. 5 | 6 | // For example, sumFibs(10) should return 10 because all odd Fibonacci numbers less than or equal to 10 are 1, 1, 3, and 5. 7 | 8 | #[allow(dead_code)] 9 | fn sum_fibs(num: i64) -> i64 { 10 | // Starting with 0 and 1 where 1 is the current number 11 | let mut prev = 0; 12 | let mut curr = 1; 13 | 14 | // Variable for storing the sum 15 | let mut sum = 0; 16 | 17 | // Loop until current number is equal to "num" argument 18 | while curr <= num { 19 | // If the current number is odd then add it to the "sum" variable 20 | if curr % 2 == 1 { 21 | sum += curr; 22 | } 23 | 24 | // The next number is the previous number added to the current number 25 | let next = prev + curr; 26 | 27 | // Rotating the number where current becomes previous and next becomes current, then 28 | // looping again 29 | prev = curr; 30 | curr = next; 31 | } 32 | sum 33 | } 34 | 35 | #[cfg(test)] 36 | mod tests { 37 | use super::*; 38 | 39 | #[test] 40 | fn test1() { 41 | assert_eq!(sum_fibs(1000), 1785); 42 | } 43 | 44 | #[test] 45 | fn test2() { 46 | assert_eq!(sum_fibs(4000000), 4613732); 47 | } 48 | 49 | #[test] 50 | fn test3() { 51 | assert_eq!(sum_fibs(4), 5); 52 | } 53 | 54 | #[test] 55 | fn test4() { 56 | assert_eq!(sum_fibs(75024), 60696); 57 | } 58 | 59 | #[test] 60 | fn test5() { 61 | assert_eq!(sum_fibs(75025), 135721); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/solutions/wherefore_art_thou.rs: -------------------------------------------------------------------------------- 1 | // Make a function that looks through an array of objects (first argument) and returns an array of all objects 2 | // that have matching name and value pairs (second argument). 3 | // Each name and value pair of the source object has to be present in the object 4 | // from the collection if it is to be included in the returned array. 5 | 6 | // For example, if the first argument is 7 | // [{ first: "Romeo", last: "Montague" }, { first: "Mercutio", last: null }, { first: "Tybalt", last: "Capulet" }], 8 | // and the second argument is { last: "Capulet" }, then you must return the third object from the array (the first argument), 9 | // because it contains the name and its value, that was passed on as the second argument. 10 | 11 | use std::collections::HashMap; 12 | 13 | #[allow(dead_code)] 14 | fn what_is_in_a_name( 15 | collection: Vec>, 16 | source: HashMap, 17 | ) -> Vec> { 18 | // Putting collection vector into consuming iterator 19 | collection 20 | .into_iter() 21 | // Filter over every HashMap in collection (obj) 22 | .filter(|obj| { 23 | source 24 | // Iterating over key, value pairs in source HashMap 25 | .iter() 26 | // Checking for all key, value pairs in source if the HashMap in the collection we 27 | // filter over contains a key of source and the value of the obj is equal the value 28 | // of the source HashMap 29 | .all(|(key, value)| obj.contains_key(key) && obj.get(key) == Some(value)) 30 | }) 31 | // Recollecting into vector again 32 | .collect() 33 | } 34 | 35 | #[cfg(test)] 36 | mod tests { 37 | use super::*; 38 | 39 | #[test] 40 | fn test1() { 41 | let collection = vec![ 42 | HashMap::from([ 43 | ("first".to_string(), "Romeo".to_string()), 44 | ("last".to_string(), "Montague".to_string()), 45 | ]), 46 | HashMap::from([ 47 | ("first".to_string(), "Mercutio".to_string()), 48 | ("last".to_string(), "null".to_string()), 49 | ]), 50 | HashMap::from([ 51 | ("first".to_string(), "Tybalt".to_string()), 52 | ("last".to_string(), "Capulet".to_string()), 53 | ]), 54 | ]; 55 | let query = HashMap::from([("last".to_string(), "Capulet".to_string())]); 56 | 57 | let result = vec![HashMap::from([ 58 | ("first".to_string(), "Tybalt".to_string()), 59 | ("last".to_string(), "Capulet".to_string()), 60 | ])]; 61 | 62 | assert_eq!(what_is_in_a_name(collection, query), result); 63 | } 64 | } 65 | --------------------------------------------------------------------------------