Решение на Сметки с ДНК от Диана Маркова

Обратно към всички решения

Към профила на Диана Маркова

Резултати

  • 20 точки от тестове
  • 1 бонус точка
  • 21 точки общо
  • 12 успешни тест(а)
  • 0 неуспешни тест(а)

Код

#[derive(Debug)]
pub struct NucleotideCounter {
pub a: usize,
pub c: usize,
pub g: usize,
pub t: usize,
}
pub fn counts(dna: &[char]) -> NucleotideCounter {
let mut a = 0_usize;
let mut c = 0_usize;
let mut g = 0_usize;
let mut t = 0_usize;
for &var in dna {
match var
{
'A' => { a = a + 1; },
'C' => { c = c + 1; },
'G' => { g = g + 1; },
'T' => { t = t + 1; },
_ => panic!("DNA sequence must contain ONLY 'a', 't', 'g', 'c' characters"),
}
}
NucleotideCounter{
a,
c,
g,
t
}
}

Можеш да съкратиш a = a + 1 до a += 1. Бих казал и че не си заслужава експлицитно да указваш 0_usize -- просто 0 щеше да сработи, защото компилатора ще се усети. Понякога е добре да сме експлицитни с цел четимост, но представи си, че сменим дефиницията от usize до u32 -- сега трябва да минем през тия константи и също да ги променим.

pub fn dna_complement(dna: &[char]) -> Vec<char> {
let len = dna.len();
//println!("{}", dna.len());
let mut complement: Vec<char> = Vec::with_capacity(len);
for i in 0..len as usize {
match dna[i] {
'A' => { complement.push('T') },
'T' => { complement.push('A'); },
'C' => { complement.push('G'); },
'G' => { complement.push('C'); },
_ => { panic!("DNA sequence must contain ONLY 'a', 't', 'g', 'c' characters"); },
}
}
complement
}
pub fn reverse_rna_complement(dna: &[char]) -> Vec<char> {
let len = dna.len();
let mut rna: Vec<char> = Vec::with_capacity(len);
for i in (0..len).rev() {
match dna[i] {
'A' => { rna.push('U') },
'T' => { rna.push('A'); },
'C' => { rna.push('G'); },
'G' => { rna.push('C'); },
_ => { panic!("DNA sequence must contain ONLY 'a', 't', 'g', 'c' characters"); },
}
}
rna
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
/// this is the basic test given
fn basic_test() {
let input: Vec<char> = "GC".chars().collect();
let counter = counts(&input);
assert_eq!(counter.g, 1);
assert_eq!(counter.c, 1);
assert_eq!(counter.a, 0);
assert_eq!(counter.t, 0);
assert_eq!(dna_complement(&input), vec!['C', 'G']);
assert_eq!(reverse_rna_complement(&input), vec!['G', 'C']);
}
/// the ones below are used to test more thoroughly
#[test]
fn test_with_longer_sequence() {
let input: Vec<char> = "GCTTAAACGT".chars().collect();
let counter = counts(&input);
assert_eq!(counter.g, 2);
assert_eq!(counter.c, 2);
assert_eq!(counter.a, 3);
assert_eq!(counter.t, 3);
assert_eq!(dna_complement(&input), vec!['C', 'G', 'A', 'A', 'T', 'T', 'T', 'G', 'C', 'A']);
assert_eq!(reverse_rna_complement(&input), vec!['A', 'C', 'G', 'U', 'U', 'U', 'A', 'A', 'G', 'C']);
}
#[test]
fn test_with_empty_sequence() {
let input: Vec<char> = "".chars().collect();
let counter = counts(&input);
assert_eq!(counter.g, 0);
assert_eq!(counter.c, 0);
assert_eq!(counter.a, 0);
assert_eq!(counter.t, 0);
assert_eq!(dna_complement(&input), vec![]);
assert_eq!(reverse_rna_complement(&input), vec![]);
}
#[test]
#[should_panic(expected = "DNA sequence must contain ONLY 'a', 't', 'g', 'c' characters")]
fn panic_test_counts() {
let input: Vec<char> = "gCTaaAAcGT".chars().collect();
let counter = counts(&input);
}
#[test]
#[should_panic(expected = "DNA sequence must contain ONLY 'a', 't', 'g', 'c' characters")]
fn panic_test_dna_complement() {
let input: Vec<char> = "gCT5aAAcGT".chars().collect();
dna_complement(&input);
}
#[test]
#[should_panic(expected = "DNA sequence must contain ONLY 'a', 't', 'g', 'c' characters")]
fn panic_test_reverse_rna() {
let input: Vec<char> = "gCT5aAAcGT".chars().collect();
reverse_rna_complement(&input);
}
}

Лог от изпълнението

Compiling solution v0.1.0 (/tmp/d20220112-2706256-tynnsm/solution)
    Finished test [unoptimized + debuginfo] target(s) in 5.68s
     Running tests/solution_test.rs (target/debug/deps/solution_test-4c880d3f0adaac34)

running 12 tests
test solution_test::test_counts_basic ... ok
test solution_test::test_counts_big ... ok
test solution_test::test_counts_panic1 - should panic ... ok
test solution_test::test_counts_panic2 - should panic ... ok
test solution_test::test_counts_zero ... ok
test solution_test::test_dna_complement_big ... ok
test solution_test::test_dna_complement_empty ... ok
test solution_test::test_dna_complement_panic - should panic ... ok
test solution_test::test_reverse_rna_complement_big ... ok
test solution_test::test_reverse_rna_complement_empty ... ok
test solution_test::test_reverse_rna_complement_panic1 - should panic ... ok
test solution_test::test_reverse_rna_complement_panic2 - should panic ... ok

test result: ok. 12 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

История (2 версии и 2 коментара)

Диана качи първо решение на 21.10.2021 18:30 (преди почти 4 години)

Диана качи решение на 21.10.2021 18:39 (преди почти 4 години)

#[derive(Debug)]
pub struct NucleotideCounter {
pub a: usize,
pub c: usize,
pub g: usize,
pub t: usize,
}
pub fn counts(dna: &[char]) -> NucleotideCounter {
let mut a = 0_usize;
let mut c = 0_usize;
let mut g = 0_usize;
let mut t = 0_usize;
for &var in dna {
match var
{
'A' => { a = a + 1; },
'C' => { c = c + 1; },
'G' => { g = g + 1; },
'T' => { t = t + 1; },
_ => panic!("DNA sequence must contain ONLY 'a', 't', 'g', 'c' characters"),
}
}
NucleotideCounter{
a,
c,
g,
t
}
}

Можеш да съкратиш a = a + 1 до a += 1. Бих казал и че не си заслужава експлицитно да указваш 0_usize -- просто 0 щеше да сработи, защото компилатора ще се усети. Понякога е добре да сме експлицитни с цел четимост, но представи си, че сменим дефиницията от usize до u32 -- сега трябва да минем през тия константи и също да ги променим.

pub fn dna_complement(dna: &[char]) -> Vec<char> {
let len = dna.len();
//println!("{}", dna.len());
let mut complement: Vec<char> = Vec::with_capacity(len);
for i in 0..len as usize {
match dna[i] {
'A' => { complement.push('T') },
'T' => { complement.push('A'); },
'C' => { complement.push('G'); },
'G' => { complement.push('C'); },
_ => { panic!("DNA sequence must contain ONLY 'a', 't', 'g', 'c' characters"); },
}
}
complement
}
pub fn reverse_rna_complement(dna: &[char]) -> Vec<char> {
let len = dna.len();
let mut rna: Vec<char> = Vec::with_capacity(len);
for i in (0..len).rev() {
match dna[i] {
'A' => { rna.push('U') },
'T' => { rna.push('A'); },
'C' => { rna.push('G'); },
'G' => { rna.push('C'); },
_ => { panic!("DNA sequence must contain ONLY 'a', 't', 'g', 'c' characters"); },
}
}
rna
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
/// this is the basic test given
- fn test_basic() {
+ fn basic_test() {
let input: Vec<char> = "GC".chars().collect();
let counter = counts(&input);
assert_eq!(counter.g, 1);
assert_eq!(counter.c, 1);
assert_eq!(counter.a, 0);
assert_eq!(counter.t, 0);
assert_eq!(dna_complement(&input), vec!['C', 'G']);
assert_eq!(reverse_rna_complement(&input), vec!['G', 'C']);
}
/// the ones below are used to test more thoroughly
#[test]
fn test_with_longer_sequence() {
let input: Vec<char> = "GCTTAAACGT".chars().collect();
let counter = counts(&input);
assert_eq!(counter.g, 2);
assert_eq!(counter.c, 2);
assert_eq!(counter.a, 3);
assert_eq!(counter.t, 3);
assert_eq!(dna_complement(&input), vec!['C', 'G', 'A', 'A', 'T', 'T', 'T', 'G', 'C', 'A']);
assert_eq!(reverse_rna_complement(&input), vec!['A', 'C', 'G', 'U', 'U', 'U', 'A', 'A', 'G', 'C']);
}
#[test]
fn test_with_empty_sequence() {
let input: Vec<char> = "".chars().collect();
let counter = counts(&input);
assert_eq!(counter.g, 0);
assert_eq!(counter.c, 0);
assert_eq!(counter.a, 0);
assert_eq!(counter.t, 0);
assert_eq!(dna_complement(&input), vec![]);
assert_eq!(reverse_rna_complement(&input), vec![]);
}
#[test]
#[should_panic(expected = "DNA sequence must contain ONLY 'a', 't', 'g', 'c' characters")]
fn panic_test_counts() {
let input: Vec<char> = "gCTaaAAcGT".chars().collect();
let counter = counts(&input);
}
#[test]
#[should_panic(expected = "DNA sequence must contain ONLY 'a', 't', 'g', 'c' characters")]
fn panic_test_dna_complement() {
let input: Vec<char> = "gCT5aAAcGT".chars().collect();
dna_complement(&input);
}
#[test]
#[should_panic(expected = "DNA sequence must contain ONLY 'a', 't', 'g', 'c' characters")]
fn panic_test_reverse_rna() {
let input: Vec<char> = "gCT5aAAcGT".chars().collect();
reverse_rna_complement(&input);
}
-}
+}

Съобщението при паника е малко misleading, понеже казва must contain ONLY 'a', 't', 'g', 'c' characters, но всъщност малките букви са забранени 😅. Иначе, тестовете не са лоши и ще ти дам бонус точка за тях, макар че имай предвид че при вход gCT5aAAcGT може програмата да panic-не защото е видяла g, но може и да panic-не защото е видяла 5. Ти вече имаш 1 тест за първото, така че се дублира проверката. Ако видиш пълния тест, нарочно съм направил тестове, които проверяват само по 1 потенциално невалидно нещо. За reverse случая, даже повтаряш само втория тест, така че ако кода ти не panic-ваше при 5 или при малка буква, тестовете ти не биха го хванали.

Не е голяма работа, просто нещо, за което да помислиш -- в идеалния случай един тест ще тества точно едно нещо. Не си заслужава човек да е твърде стриктен за такова правило, просто е добър rule of thumb. Иначе подхода ти "какво се случва в добрия случай, какво може да се случи при лош вход", е добро начало.