Last active
December 28, 2020 07:39
-
-
Save fallwith/c48431f520904b7656298c47dcc6882c to your computer and use it in GitHub Desktop.
A Rust attempt at a Ruby challenge
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use chrono::{DateTime, Local}; | |
use std::collections::HashMap; | |
use std::env; | |
use std::process; | |
use std::time::SystemTime; | |
const VERSION: &str = "0.1.0"; | |
// a Rust attempt at the following Ruby coding challenge: | |
// https://gist.github.com/fallwith/00aa5f7a0d5c192e91fa6468e7434048 | |
fn main() { | |
let start_time = SystemTime::now(); | |
let args: Vec<String> = env::args().collect(); | |
let input = process_cli_args(&args); | |
let mut processor = PeanutsProcessor { | |
// 2. | |
names: input.split('|').map(String::from).collect(), | |
}; | |
// 3. | |
processor.add_name(String::from("Franklin")); | |
processor.add_name(String::from("Sally")); | |
// 4. | |
processor.remove_last_name(); | |
// 5. | |
let l_count = processor.starts_with_count(String::from("L")); | |
// 6. | |
let over_4_count = processor.over_n_count(4); | |
// 7. | |
let substring_matches_included_list = processor.names.clone(); | |
let unwanted_substring = String::from("ie"); | |
processor.remove_having_substring(unwanted_substring.clone()); | |
let substring_matches_removed_list = processor.names.clone(); | |
// 8 | |
processor.sort_names(); | |
// 9. | |
let seen_counts = processor.seen_counts(); | |
// 10. | |
processor.dedup_names(); | |
// 11. | |
let labeled_list = processor.labeled_list(); | |
println!("{}", labeled_list); | |
// 12. | |
let semicoloned_peanuts = processor.delimit_names(String::from(";")); | |
// 13. | |
let datetime: DateTime<Local> = start_time.into(); | |
println!(); | |
println!( | |
"Program started at {}", | |
datetime.format("%m/%d/%y at %I:%M %p") | |
); | |
println!("Program version = {}", VERSION); | |
println!("Original delimited string: '{}'", input); | |
println!("'L' name count is {}", l_count); | |
println!("Over 4 characters name count is {}", over_4_count); | |
println!("Unwanted substring = '{}'", unwanted_substring); | |
println!( | |
"List before removing substring matches: '{}'", | |
substring_matches_included_list.join("|") | |
); | |
println!( | |
"List after removing substring matches: '{}'", | |
substring_matches_removed_list.join("|") | |
); | |
println!("Number of times each name appears:"); | |
for (name, count) in seen_counts { | |
println!("{} => {}", name, count); | |
} | |
println!( | |
"Sorted, substring filtered, de-duped list with English word labels:\n{}", | |
labeled_list | |
); | |
println!("New delimited string: {}", semicoloned_peanuts); | |
match start_time.elapsed() { | |
Ok(elapsed) => { | |
println!( | |
"Elapsed time: {:.3} secs", | |
(elapsed.as_millis() as f64) / 1000.0 | |
); | |
} | |
Err(e) => { | |
println!("Failed to determine elapsed time! - {:?}", e); | |
} | |
} | |
} | |
// 16. | |
pub fn process_cli_args(args: &[String]) -> String { | |
for arg in args { | |
if arg == "-h" || arg == "--help" { | |
println!( | |
"Usage: {}\n\n\tor:\n\n{} Name1 Name2 Name3", | |
args[0], args[0] | |
); | |
process::exit(0); | |
} else if arg == "-v" || arg == "--version" { | |
println!("Version: {}", VERSION); | |
process::exit(0); | |
} else if arg.starts_with('-') { | |
panic!("Unexpected argument '{}'", arg) | |
} | |
} | |
match args.len() { | |
// 1. | |
1 => String::from("Charlie|Snoopy|Linus|Lucy|Linus|Pigpen|Snoopy|Linus|Woodstock|Frieda"), | |
// 14. | |
2..=3 => { | |
panic!("Too few names - please provide 4 to 10 names or none for the default list") | |
} | |
4..=11 => args[1..].join("|"), | |
_ => panic!("Too many names - please provide 4 to 10 names or none for the default list"), | |
} | |
} | |
// 15. sorta, no classes in Rust | |
struct PeanutsProcessor { | |
names: Vec<String>, | |
} | |
impl PeanutsProcessor { | |
fn add_name(&mut self, name: String) { | |
self.names.push(name); | |
} | |
fn remove_last_name(&mut self) { | |
self.names.pop(); | |
} | |
fn starts_with_count(&mut self, initial: String) -> u32 { | |
let mut count: u32 = 0; | |
for name in &self.names { | |
if name.starts_with(&initial) { | |
count += 1; | |
} | |
} | |
count | |
} | |
fn over_n_count(&mut self, threshold: usize) -> u32 { | |
let mut count: u32 = 0; | |
for name in &self.names { | |
if name.chars().count() > threshold { | |
count += 1; | |
} | |
} | |
count | |
} | |
fn remove_having_substring(&mut self, substring: String) { | |
&self.names.retain(|name| !name.contains(&substring)); | |
} | |
fn sort_names(&mut self) { | |
self.names.sort(); | |
} | |
fn seen_counts(&mut self) -> HashMap<String, u32> { | |
let mut counts: HashMap<String, u32> = HashMap::new(); | |
for name in &self.names { | |
let count = counts.entry(name.to_string()).or_insert(0); | |
*count += 1; | |
} | |
counts | |
} | |
fn dedup_names(&mut self) { | |
self.names.dedup(); | |
} | |
fn labeled_list(&mut self) -> String { | |
let english_number_words: HashMap<usize, &str> = [ | |
(1, "One"), | |
(2, "Two"), | |
(3, "Three"), | |
(4, "Four"), | |
(5, "Five"), | |
(6, "Six"), | |
(7, "Seven"), | |
(8, "Eight"), | |
(9, "Nine"), | |
(10, "Ten"), | |
(11, "Eleven"), // input max is 10, 2 get added, and 1 gets removed | |
] | |
.iter() | |
.cloned() | |
.collect(); | |
let mut list: String = String::new(); | |
for (idx, name) in self.names.iter().enumerate() { | |
let formatted = format!("Item {}:\t{}\n", english_number_words[&(idx + 1)], name); | |
list = format!("{}{}", list, formatted); | |
} | |
list.pop(); | |
list | |
} | |
fn delimit_names(&mut self, delimiter: String) -> String { | |
self.names.join(&delimiter) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment