From c13639c6f91ac2452b57a3b12bed21534730e550 Mon Sep 17 00:00:00 2001 From: Peter Tseng Date: Sat, 5 Nov 2016 00:27:49 -0700 Subject: [PATCH 1/3] nucleotide-count: Error on invalid nucleotide `count` and `nucleotide_counts` both return a Result now. Closes #149 --- config.json | 1 + exercises/nucleotide-count/example.rs | 25 +++++++++++++----- .../tests/nucleotide-count.rs | 26 ++++++++++++++++--- problems.md | 2 +- 4 files changed, 43 insertions(+), 11 deletions(-) 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..2b2e91da0 100644 --- a/exercises/nucleotide-count/example.rs +++ b/exercises/nucleotide-count/example.rs @@ -1,13 +1,26 @@ use std::collections::HashMap; +use std::collections::hash_map::Entry; -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; + match map.entry(nucleotide) { + Entry::Vacant(_) => return Err(nucleotide), + Entry::Occupied(mut view) => { + *view.get_mut() += 1; + } + } } - map + Ok(map) } diff --git a/exercises/nucleotide-count/tests/nucleotide-count.rs b/exercises/nucleotide-count/tests/nucleotide-count.rs index 32640dabb..3d9ec68e2 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)); } @@ -17,19 +17,31 @@ fn check_dna(s: &str, pairs: &[(char, usize)]) { #[test] 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] @@ -56,3 +68,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 From cf669e02f97e9f82079eeaed00db95aa6a292749 Mon Sep 17 00:00:00 2001 From: Peter Tseng Date: Wed, 4 Jan 2017 22:55:18 -0800 Subject: [PATCH 2/3] nucleotide-count: Use if-let rather than Entry --- exercises/nucleotide-count/example.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/exercises/nucleotide-count/example.rs b/exercises/nucleotide-count/example.rs index 2b2e91da0..603e1a4bf 100644 --- a/exercises/nucleotide-count/example.rs +++ b/exercises/nucleotide-count/example.rs @@ -1,5 +1,4 @@ use std::collections::HashMap; -use std::collections::hash_map::Entry; static VALID_NUCLEOTIDES: &'static str = "ACGT"; @@ -15,11 +14,10 @@ pub fn count(nucleotide: char, input: &str) -> Result { 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() { - match map.entry(nucleotide) { - Entry::Vacant(_) => return Err(nucleotide), - Entry::Occupied(mut view) => { - *view.get_mut() += 1; - } + if let Some(n) = map.get_mut(&nucleotide) { + *n += 1; + } else { + return Err(nucleotide); } } Ok(map) From 789e0388e5215e7653a559d6829c9bd4992d649e Mon Sep 17 00:00:00 2001 From: Peter Tseng Date: Thu, 5 Jan 2017 09:21:15 -0800 Subject: [PATCH 3/3] nucleotide-count: Add is_ok tests --- exercises/nucleotide-count/tests/nucleotide-count.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/exercises/nucleotide-count/tests/nucleotide-count.rs b/exercises/nucleotide-count/tests/nucleotide-count.rs index 3d9ec68e2..bf5fddf28 100644 --- a/exercises/nucleotide-count/tests/nucleotide-count.rs +++ b/exercises/nucleotide-count/tests/nucleotide-count.rs @@ -16,6 +16,12 @@ 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', "").unwrap(), 0); } @@ -44,6 +50,12 @@ fn test_count_only_thymine() { assert_eq!(dna::count('T', "GGGGGTAACCCGG").unwrap(), 1); } +#[test] +#[ignore] +fn counts_returns_result() { + assert!(dna::nucleotide_counts("ACGT").is_ok()); +} + #[test] #[ignore] fn test_nucleotide_count_empty() {