Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions config.json
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@
"slug": "nucleotide-count",
"difficulty": 1,
"topics": [
"Result",
"filter",
"entry api",
"mutablity",
Expand Down
23 changes: 17 additions & 6 deletions exercises/nucleotide-count/example.rs
Original file line number Diff line number Diff line change
@@ -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<usize, char> {
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)
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for count('A', "AX") this returns A instead of X, but we don't check it in the tests so I'm not motivated.

}
}

pub fn nucleotide_counts(input: &str) -> HashMap<char, usize> {
let mut map: HashMap<char, usize> = "ACGT".chars().map(|c| (c, 0)).collect();
pub fn nucleotide_counts(input: &str) -> Result<HashMap<char, usize>, char> {
let mut map: HashMap<char, usize> = 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)
}
38 changes: 34 additions & 4 deletions exercises/nucleotide-count/tests/nucleotide-count.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<char, usize> = dna::nucleotide_counts(s);
let mut m: HashMap<char, usize> = dna::nucleotide_counts(s).unwrap();
for &(k, v) in pairs.iter() {
assert_eq!((k, m.remove(&k).unwrap()), (k, v));
}
Expand All @@ -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);
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we do anything specific here to make abundandly clear that it's a result? see https://github.com/exercism/xrust/blob/master/exercises/largest-series-product/tests/largest-series-product.rs#L6

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think using is_err is enough.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. For implementations that expect Result or Option, I usually start with some is_err and is_ok tests just to make it clear.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added. One for each function.

}

#[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]
Expand All @@ -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());
}
2 changes: 1 addition & 1 deletion problems.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

duped, but to be solved by #236

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
Expand Down