Сметки с ДНК

Предадени решения

Краен срок:
26.10.2021 17:00
Точки:
20

Срокът за предаване на решения е отминал

#[test]
fn test_counts_zero() {
let counter = solution::counts(&[]);
assert_eq!(counter.g, 0);
assert_eq!(counter.c, 0);
assert_eq!(counter.a, 0);
assert_eq!(counter.t, 0);
}
#[test]
fn test_counts_basic() {
let counter = solution::counts(&['A', 'G', 'C', 'T']);
assert_eq!(counter.g, 1);
assert_eq!(counter.c, 1);
assert_eq!(counter.a, 1);
assert_eq!(counter.t, 1);
}
#[test]
#[should_panic]
fn test_counts_panic1() {
solution::counts(&['A', 'X', 'C']);
}
#[test]
#[should_panic]
fn test_counts_panic2() {
solution::counts(&['a', 'g', 'c']);
}
#[test]
fn test_counts_big() {
let input: Vec<char> =
"AGCTTTTCATTCTGACTGCAACGGGCAATATGTCTCTGTGTGGATTAAAAAAAGAGTGTCTGATAGCAGC".chars().collect();
let counter = solution::counts(&input);
assert_eq!(counter.g, 17);
assert_eq!(counter.c, 12);
assert_eq!(counter.a, 20);
assert_eq!(counter.t, 21);
}
#[test]
fn test_dna_complement_empty() {
assert_eq!(solution::dna_complement(&[]), Vec::new());
}
#[test]
#[should_panic]
fn test_dna_complement_panic() {
solution::dna_complement(&['X']);
}
#[test]
fn test_dna_complement_big() {
let input: Vec<char> =
"AGCTTTTCATTCTGACTGCAACGGGCAATATGTCTCTGTGTGGATTAAAAAAAGAGTGTCTGATAGCAGC".chars().collect();
let expected_output: Vec<char> =
"TCGAAAAGTAAGACTGACGTTGCCCGTTATACAGAGACACACCTAATTTTTTTCTCACAGACTATCGTCG".chars().collect();
assert_eq!(solution::dna_complement(&input), expected_output);
}
#[test]
fn test_reverse_rna_complement_empty() {
assert_eq!(solution::reverse_rna_complement(&[]), Vec::new());
}
#[test]
#[should_panic]
fn test_reverse_rna_complement_panic1() {
solution::reverse_rna_complement(&['X']);
}
#[test]
#[should_panic]
fn test_reverse_rna_complement_panic2() {
solution::reverse_rna_complement(&['U']);
}
#[test]
fn test_reverse_rna_complement_big() {
let input: Vec<char> =
"AGCTTTTCATTCTGACTGCAACGGGCAATATGTCTCTGTGTGGATTAAAAAAAGAGTGTCTGATAGCAGC".chars().collect();
let mut expected_output: Vec<char> =
"UCGAAAAGUAAGACUGACGUUGCCCGUUAUACAGAGACACACCUAAUUUUUUUCUCACAGACUAUCGUCG".chars().collect();
expected_output.reverse();
assert_eq!(solution::reverse_rna_complement(&input), expected_output);
}

Време е за биоинформатика. И под "биоинформатика" имаме предвид броене на char-ове.

Броене

Една нишка ДНК е съставена от комбинация от четири нуклеотидни бази -- цитозин, гуанин, аденин и тимин, които се описват с буквите C, G, A, T. Като за начало, искаме да напишете функция, която приема slice от тези бази и брои колко пъти се срещат:

pub struct NucleotideCounter {
    pub a: usize,
    pub c: usize,
    pub g: usize,
    pub t: usize,
}

pub fn counts(dna: &[char]) -> NucleotideCounter {
    todo!()
}

Входа ще бъде списък, който изглежда примерно така: ['A', 'C', 'G', 'A', 'T', ...]. Всеки път като срещнете един от тези четири символа, очакваме да го преброите в съответното поле в този counter и да го върнете накрая.

Hint: Може да минете по елементите на един списък с for-цикъл, има пример още в първата лекция.

В случай, че ви подадем буквичка, която не е една от тези, ще очакваме да panic-нете. Това включва малките букви a, g, и т.н. -- само големите букви са валидни, само тези четири. Тъй като още не сме говорили за error handling, ето какво значи "да panic-нете":

panic!("Грешка, грешка, обърках вратата");

Самото съобщение е ваш избор и, технически погледнато, не е нужно да съдържа цитат от песен на Джанго Зе.

Комплементарно ДНК

ДНК-то се състои от две нишки, които са свързани база с база. Всяка база си има конкретно приятелче, с което се връзва:

  • Базата G се свързва само с базата C и обратно
  • Базата A се свързва само с базата T и обратно

В следващата функция искаме да ни дадете тази нишка, която се връзва с подадената, база по база:

pub fn dna_complement(dna: &[char]) -> Vec<char> {
    todo!()
}

И така, dna_complement(&['A', 'C']) ще очакваме да ни върне вектор с първи елемент 'T' и втори елемент 'G'. Както при първата функция, очакваме ако подадем различна буква от тези четири, да panic-нете.

РНК

ДНК е "шаблона", програмата, от която се започва. Молекулата РНК минава по ДНК-то, копира го и отива да прави протеини. Тя има само една нишка и вместо базата тимин (T) използва базата урацил (U), която работи по същия начин -- свързва се с аденозин (A).

Другото интересно нещо е че нишката се чете наобратно, или поне нещо такова помним бегло и смело ще използваме като оправдание да ви накараме да итерирате наобратно за разнообразие:

pub fn reverse_rna_complement(dna: &[char]) -> Vec<char> {
    todo!()
}

Тази функция очакваме да ни даде "complement" на подадената нишка, също както предната функция. За да бъде максимално ясно:

  • Входа на функцията е ДНК, комбинация от базите: G, C, A, T
  • Изхода на функцията е РНК, комбинация от базите: G, C, A, U

Тоест, вместо T ще очакваме в резултата да присъства базата U, и нишката трябва да е обърната. Примерно, reverse_rna_complement(&['A', 'C']) би трябвало да върне вектор с първи елемент 'G' и втори елемент 'U'.

Вероятно ще е най-лесно да обърнете резултатния вектор, което звучи като нещо, което може да е описано някъде в документацията на стандартната библиотека.

Пак, очакваме паника при неочакван символ. Входа е ДНК, така че четирите символа за валидация са непроменени, само изхода ще бъде различен.

Бележки

Не се притеснявайте за скорост, примерно спокойно си обръщайте вектори както си искате. В силно вероятния случай да сме объркали терминологията или нещо такова, не забравяйте че не сме биолози :). Следвайте инструкциите на задачката, питайте ако има нещо неясно.

Задължително прочетете (или си припомнете): Указания за предаване на домашни

Погрижете се решението ви да се компилира с базовия тест:

use solution::*;
#[test]
fn test_basic() {
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']);
}