diff --git a/config.json b/config.json index 51f434b0b..d42737d53 100644 --- a/config.json +++ b/config.json @@ -115,6 +115,7 @@ "slug": "nucleotide-count", "difficulty": 1, "topics": [ + "Result", "filter", "entry api", "mutablity", diff --git a/exercises/nucleotide-count/example.rs b/exercises/nucleotide-count/example.rs index 0c389921a..603e1a4bf 100644 --- a/exercises/nucleotide-count/example.rs +++ b/exercises/nucleotide-count/example.rs @@ -1,13 +1,24 @@ use std::collections::HashMap; -pub fn count(nucleotide: char, input: &str) -> usize { - input.chars().filter(|&c| c == nucleotide).count() +static VALID_NUCLEOTIDES: &'static str = "ACGT"; + +pub fn count(nucleotide: char, input: &str) -> Result { + let valid = |x: char| { VALID_NUCLEOTIDES.contains(x) }; + if valid(nucleotide) && input.chars().all(valid) { + Ok(input.chars().filter(|&c| c == nucleotide).count()) + } else { + Err(nucleotide) + } } -pub fn nucleotide_counts(input: &str) -> HashMap { - let mut map: HashMap = "ACGT".chars().map(|c| (c, 0)).collect(); +pub fn nucleotide_counts(input: &str) -> Result, char> { + let mut map: HashMap = VALID_NUCLEOTIDES.chars().map(|c| (c, 0)).collect(); for nucleotide in input.chars() { - *map.entry(nucleotide).or_insert(0) += 1; + if let Some(n) = map.get_mut(&nucleotide) { + *n += 1; + } else { + return Err(nucleotide); + } } - map + Ok(map) } diff --git a/exercises/nucleotide-count/tests/nucleotide-count.rs b/exercises/nucleotide-count/tests/nucleotide-count.rs index 32640dabb..bf5fddf28 100644 --- a/exercises/nucleotide-count/tests/nucleotide-count.rs +++ b/exercises/nucleotide-count/tests/nucleotide-count.rs @@ -7,7 +7,7 @@ fn check_dna(s: &str, pairs: &[(char, usize)]) { // message for assert_eq! is as informative as possible. A simpler // solution would simply check the length of the map, and then // check for the presence and value of each key in the given pairs vector. - let mut m: HashMap = dna::nucleotide_counts(s); + let mut m: HashMap = dna::nucleotide_counts(s).unwrap(); for &(k, v) in pairs.iter() { assert_eq!((k, m.remove(&k).unwrap()), (k, v)); } @@ -16,20 +16,44 @@ fn check_dna(s: &str, pairs: &[(char, usize)]) { } #[test] +fn count_returns_result() { + assert!(dna::count('A', "").is_ok()); +} + +#[test] +#[ignore] fn test_count_empty() { - assert_eq!(dna::count('A', ""), 0); + assert_eq!(dna::count('A', "").unwrap(), 0); +} + +#[test] +#[ignore] +fn count_invalid_nucleotide() { + assert!(dna::count('X', "A").is_err()); +} + +#[test] +#[ignore] +fn count_invalid_dna() { + assert!(dna::count('A', "AX").is_err()); } #[test] #[ignore] fn test_count_repetitive_cytosine() { - assert_eq!(dna::count('C', "CCCCC"), 5); + assert_eq!(dna::count('C', "CCCCC").unwrap(), 5); } #[test] #[ignore] fn test_count_only_thymine() { - assert_eq!(dna::count('T', "GGGGGTAACCCGG"), 1); + assert_eq!(dna::count('T', "GGGGGTAACCCGG").unwrap(), 1); +} + +#[test] +#[ignore] +fn counts_returns_result() { + assert!(dna::nucleotide_counts("ACGT").is_ok()); } #[test] @@ -56,3 +80,9 @@ fn test_nucleotide_count_counts_all() { GAGTGTCTGATAGCAGC", &[('A', 20), ('T', 21), ('C', 12), ('G', 17)]); } + +#[test] +#[ignore] +fn counts_invalid_nucleotide_results_in_err() { + assert!(dna::nucleotide_counts("GGXXX").is_err()); +} diff --git a/problems.md b/problems.md index cc2a5db04..6993674c3 100644 --- a/problems.md +++ b/problems.md @@ -36,7 +36,7 @@ hamming | Result pascals-triangle | Math, Vec, Index (optional) scrabble-score | chaining higher-order functions, HashMap (optional) pangram | filter, ascii (optional) -nucleotide-count | filter, entry api, mutablity, match +nucleotide-count | Result, filter, entry api, mutablity, match largest-series-product | Result, windows, higher-order functions, char word-count | hashmap, str vs string, chars, entry api atbash-cipher | str vs string, primitive types, iterators, chars, ascii