Решение на Дигитален корен от Катерина Манева

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

Към профила на Катерина Манева

Резултати

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

Код

use std::char::from_digit;
#[cfg(test)]
mod tests {
#[test]
fn test_num_to_string() {
assert_eq!("5", super::num_to_string(5, 10));
assert_eq!("12", super::num_to_string(12, 10));
assert_eq!("c", super::num_to_string(12, 16));
assert_eq!("10", super::num_to_string(16, 16));
assert_eq!("12", super::num_to_string(10, 8));
}
#[test]
fn test_correct_input() {
assert!(!super::correct_input("80", 8));
assert!(super::correct_input("0", 8));
assert!(super::correct_input("101", 2));
assert!(super::correct_input("0111", 2));
assert!(super::correct_input("7b", 16));
assert!(!super::correct_input("7B", 16));
assert!(super::correct_input("9989", 10));
assert!(!super::correct_input("9a", 10));
assert!(!super::correct_input("g", 16));
assert!(!super::correct_input("А", 16))
}
}

Имаш някоя и друга дупка в тестовете. Примерно, добре проверяваш за невалиден вход за няколко бройни системи, но за двоична бройна система имаш само положителни примери. Все пак са някакви тестове и ще ти дам точка за тях, но за следващото домашно ще съм по-придирчив за бонусите :).

//Ф-ия намираща dr по зададен низ и бройна с-ма
fn digital_root(string: &str, base: u32) -> char {
let length = string.len();
if length == 1 {
return string.chars().next().unwrap();
}
let mut sum = 0;
for ch in string.chars() {
let digit = ch.to_digit(base);
debug_assert!(digit.is_some());
sum += digit.unwrap();
}
let sum_in_string = num_to_string(sum, base);
return digital_root(&sum_in_string, base);
}

Вместо да връщаш char, може би щеше да е по-удобно директно да връщаш u32 като извикаш .to_digit(base) на .chars().next().unwrap(). Така щеше да си спестиш едно допълнително извикване в индивидуалните методи.

Можеше и да избегнеш .unwrap-овете (или поне част от тях) като върнеш None ако не проработят. Т.е. вместо да валидираш в отделна функция, спокойно можеше digital_root да върне Option<char> (или Option<u32> в комбинация с предния съвет) и да сложиш един match statement.

fn num_to_string(num: u32, base: u32) -> String {
let mut result_string = String::from("");
let mut number = num;
while number > 0 {
let number_in_char = from_digit(number % base, base);
debug_assert!(number_in_char.is_some());
let num_in_char = number_in_char.unwrap();
result_string.insert(0, num_in_char);
number /= base;
}
result_string
}
fn incorrect_char(ch : char, base: u32) -> bool {
!ch.is_digit(base) || (ch >= 'A' && ch <= 'Z')
}

Не е необходимо да валидираш, че буквите са малки. В условието казахме "ще подаваме само малки букви, тоест "7b" но не "7B", което не значи, че големите букви са невалидни, просто значи, че ние няма да тестваме с тях, така че не е нужно да проверявате.

fn correct_input(string: &str, base:u32) -> bool {
let mut result = true;
for ch in string.chars() {
if incorrect_char(ch, base) {
result = false;
break;
}
}
result
}
/// Десетична бройна система: 0-9
pub fn decimal(input: &str) -> Option<u32> {
if !correct_input(input, 10) {
return None;
}
let dr = digital_root(input, 10);
dr.to_digit(10)
}
/// Шестнадесетична бройна система: 0-9, последвано от a-f
pub fn hex(input: &str) -> Option<u32> {
if !correct_input(input, 16) {
return None;
}
let dr = digital_root(input, 16);
dr.to_digit(16)
}
/// Осмична бройна система: 0-7
pub fn octal(input: &str) -> Option<u32> {
if !correct_input(input, 8) {
return None;
}
let dr = digital_root(input, 8);
dr.to_digit(8)
}
/// Двоична бройна система: 0-1
pub fn binary(input: &str) -> Option<u32> {
if !correct_input(input, 2) {
return None;
}
let dr = digital_root(input, 2);
dr.to_digit(2)
}

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

Compiling solution v0.1.0 (/tmp/d20200111-2173579-1pd3bzl/solution)
    Finished test [unoptimized + debuginfo] target(s) in 3.17s
     Running target/debug/deps/solution-a73e64ec87929bd0

running 2 tests
test tests::test_correct_input ... ok
test tests::test_num_to_string ... ok

test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out

     Running target/debug/deps/solution_test-38971695424b36d5

running 6 tests
test solution_test::test_binary ... ok
test solution_test::test_decimal_basic ... ok
test solution_test::test_hex_basic ... ok
test solution_test::test_invalid ... ok
test solution_test::test_octal_basic ... ok
test solution_test::test_zeroes ... ok

test result: ok. 6 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out

   Doc-tests solution

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out

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

Катерина качи първо решение на 05.11.2019 11:32 (преди почти 6 години)

Разумно решение. Бих те посъветвал да експериментираш с опционалност -- вместо да викаш .is_digit и после .to_digit().unwrap(), можеш директно да използваш факта, че .to_digit() ще ти даде валидна стойност или None. Оператора ? работи и за Option, така че това може да опрости подобни операции значително.