Решение на Matrix 4 от Ростислав Цачев

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

Към профила на Ростислав Цачев

Резултати

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

Код

use std::ops::Add;
use std::ops::Mul;
#[derive(Debug)]
pub struct Matrix<T: Clone> {
data: Vec<Vec<Cell<T>>>,
size: usize // In our case will be 2, but we are thinking in a general way :)
}
#[derive(Debug, Clone, PartialEq)]
pub struct Cell<T>(pub T);
impl<T: Clone> Matrix<T> {
pub fn new(data: &[T; 4]) -> Matrix<T> {
let size: usize = 2;
let mut data_index = 0;
let mut matrix_data = Vec::new();
for row in 0..size {
matrix_data.push(Vec::new());
for _ in 0..size {
matrix_data[row].push(Cell(data[data_index].clone()));
data_index += 1;
}
}
Matrix { data: matrix_data, size }
}
pub fn by_row(&self) -> Vec<Cell<T>> {
let mut result = Vec::new();
for row in 0..self.size {
for col in 0..self.size {
result.push(self.data[row][col].clone());
}
}
result
}
pub fn by_col(&self) -> Vec<Cell<T>> {
let mut result = Vec::new();
for col in 0..self.size {
for row in 0..self.size {
result.push(self.data[row][col].clone());
}
}
result
}
}
impl Add<Cell<String>> for Cell<i32> {
type Output = Cell<String>;
fn add(self, other: Cell<String>) -> Cell<String> {
fn add_with_negative_number(this: Cell<i32>, other: Cell<String>) -> Cell<String> {
let mut result = Cell(String::new());
let abs_value = -1 * this.0;
(result.0).push_str(&other.0);
result.0 = (result.0).chars().rev().collect();
(result.0).push(' ');
(result.0).push_str(&abs_value.to_string());
result
}
fn add_with_non_negative_number(this: Cell<i32>, other: Cell<String>) -> Cell<String> {
let mut result = Cell(String::new());
let abs_value = this.0;
(result.0).push_str(&abs_value.to_string());
(result.0).push(' ');
(result.0).push_str(&other.0);
result
}
let cell_number = self.0;
if cell_number < 0 {
add_with_negative_number(self, other)
} else {
add_with_non_negative_number(self, other)
}
}
}
impl Mul<Cell<String>> for Cell<i32> {
type Output = Cell<String>;
fn mul(self, other: Cell<String>) -> Cell<String> {
let mut result = Cell(String::new());
let cell_number = self.0;
let mut abs_value = cell_number;
let mut repetition_string = other.0;
if cell_number < 0 {
abs_value *= -1;
repetition_string = repetition_string.chars().rev().collect();
}
for _ in 0..abs_value {
(result.0).push_str(&repetition_string);
}
result
}
}
impl Add<Matrix<String>> for Matrix<i32> {
type Output = Matrix<String>;
fn add(self, other: Matrix<String>) -> Matrix<String> {
let mut result_data: [String; 4] = [String::new(), String::new(), String::new(), String::new()];
let mut result_index = 0;
for row in 0..self.size {
for col in 0..self.size {
let result_cell = self.data[row][col].clone() + other.data[row][col].clone();
result_data[result_index].push_str(&result_cell.0);
result_index += 1;
}
}
Matrix::new(&result_data)
}
}
impl Mul<Matrix<String>> for Matrix<i32> {
type Output = String;
fn mul(self, other: Matrix<String>) -> String {
let mut result = String::new();
for i in 0..self.size {
for j in 0..self.size {
let current_cell = self.data[i][j].clone() * other.data[j][i].clone();
if i != 0 || j != 0 {
result.push(' ');
}
result.push_str(&current_cell.0);
}
}
result
}
}
#[cfg(test)]
mod tests {
use super::*;
// За помощни цели:
fn string_cell_vec(s1: &str, s2: &str, s3: &str, s4: &str) -> Vec<Cell<String>> {
[s1, s2, s3, s4].into_iter().map(String::from).map(Cell).collect::<Vec<Cell<String>>>()
}
#[test]
fn test_basic() {
assert_eq!((Cell(4) + Cell(String::from("badger"))).0, String::from("4 badger"));
assert_eq!((Cell(2) * Cell(String::from("mushroom"))).0, String::from("mushroommushroom"));
let matrix1 = Matrix::new(&[1, 2, 3, 4]);
let matrix2 = Matrix::new(&[
String::from("one"), String::from("two"),
String::from("three"), String::from("four")
]);
assert_eq!(matrix1.by_row()[0], Cell(1));
assert_eq!(matrix1.by_col()[0], Cell(1));
assert_eq!(
(matrix1 + matrix2).by_row(),
string_cell_vec("1 one", "2 two", "3 three", "4 four")
);
let matrix1 = Matrix::new(&[1, 1, 1, 1]);
let matrix2 = Matrix::new(&[
String::from("one"), String::from("two"),
String::from("three"), String::from("four")
]);
assert_eq!(matrix1 * matrix2, String::from("one three two four"));
}
mod cells {
use super::*;
mod add {
use super::*;
#[test]
fn test_non_negative_first_argument() {
assert_eq!((Cell(0) + Cell(String::from("gdfgkdfg"))).0, String::from("0 gdfgkdfg"));
assert_eq!((Cell(123) + Cell(String::from(" 0"))).0, String::from("123 0"));
assert_eq!((Cell(45) + Cell(String::from(" gasds23weq2314sg"))).0, String::from("45 gasds23weq2314sg"));
assert_eq!((Cell(234234) + Cell(String::from(""))).0, String::from("234234 "));
assert_eq!((Cell(5) + Cell(String::from("явекявекоас"))).0, String::from("5 явекявекоас"));
assert_eq!((Cell(6) + Cell(String::from("*$%^%^&(&*()"))).0, String::from("6 *$%^%^&(&*()"));
}
#[test]
fn test_negative_first_argument() {
let mut expected = "явекявекоас".chars().rev().collect::<String>();
expected.push_str(" 5");
assert_eq!((Cell(-5) + Cell(String::from("явекявекоас"))).0, expected);
expected = "asdasdasf".chars().rev().collect::<String>();
expected.push_str(" 12");
assert_eq!((Cell(-12) + Cell(String::from("asdasdasf"))).0, expected);
expected = " 123".chars().rev().collect::<String>();
expected.push_str(" 124");
assert_eq!((Cell(-124) + Cell(String::from(" 123"))).0, expected);
expected = String::from("");
expected.push_str(" 236");
assert_eq!((Cell(-236) + Cell(String::from(""))).0, expected);
}
}
mod mul {
use super::*;
#[test]
fn test_non_negative_first_argument() {
assert_eq!((Cell(2) * Cell(String::from("sadasdsaf"))).0, String::from("sadasdsafsadasdsaf"));
assert_eq!((Cell(0) * Cell(String::from("sdsdfkjsdfkjsdf"))).0, String::from(""));
assert_eq!((Cell(1) * Cell(String::from("dskfjjritre"))).0, String::from("dskfjjritre"));
assert_eq!((Cell(5) * Cell(String::from("й!фги$е№йфо"))).0, String::from("й!фги$е№йфой!фги$е№йфой!фги$е№йфой!фги$е№йфой!фги$е№йфо"));
assert_eq!((Cell(3) * Cell(String::from(""))).0, String::from(""));
assert_eq!((Cell(3) * Cell(String::from(" "))).0, String::from(" "));
}
#[test]
fn test_negative_first_argument() {
let mut expected = "sadasdsafsadasdsaf".chars().rev().collect::<String>();
assert_eq!((Cell(-2) * Cell(String::from("sadasdsaf"))).0, expected);
expected = "dskfjjritre".chars().rev().collect::<String>();
assert_eq!((Cell(-1) * Cell(String::from("dskfjjritre"))).0, expected);
expected = "й!фги$е№йфой!фги$е№йфой!фги$е№йфой!фги$е№йфой!фги$е№йфо".chars().rev().collect::<String>();
assert_eq!((Cell(-5) * Cell(String::from("й!фги$е№йфо"))).0, expected);
assert_eq!((Cell(-3) * Cell(String::from(""))).0, String::from(""));
assert_eq!((Cell(-3) * Cell(String::from(" "))).0, String::from(" "));
}
}
}
mod matrices {
use super::*;
#[test]
fn test_int_new() {
let int_data: [i32; 4] = [-1, 0,
4, 12];
let int_matrix = Matrix::new(&int_data);
assert_eq!(int_matrix.data[0][0], Cell(int_data[0]));
assert_eq!(int_matrix.data[0][1], Cell(int_data[1]));
assert_eq!(int_matrix.data[1][0], Cell(int_data[2]));
assert_eq!(int_matrix.data[1][1], Cell(int_data[3]));
let int_data2: [i32; 4] = [123, 5,
-1234, 142];
let int_matrix2 = Matrix::new(&int_data2);
assert_eq!(int_matrix2.data[0][0], Cell(int_data2[0]));
assert_eq!(int_matrix2.data[0][1], Cell(int_data2[1]));
assert_eq!(int_matrix2.data[1][0], Cell(int_data2[2]));
assert_eq!(int_matrix2.data[1][1], Cell(int_data2[3]));
}
#[test]
fn test_string_new() {
let string_data: [String; 4] = [String::from(""), String::from("12"),
String::from("fasfasfwe"), String::from("^%&#$%SDF")];
let string_matrix = Matrix::new(&string_data);
assert_eq!(string_matrix.data[0][0], Cell(string_data[0].clone()));
assert_eq!(string_matrix.data[0][1], Cell(string_data[1].clone()));
assert_eq!(string_matrix.data[1][0], Cell(string_data[2].clone()));
assert_eq!(string_matrix.data[1][1], Cell(string_data[3].clone()));
let string_data2: [String; 4] = [String::from(" "), String::from("1 3"),
String::from("АСДгфдмирер"), String::from("@АС%$№СДФ^&")];
let string_matrix2 = Matrix::new(&string_data2);
assert_eq!(string_matrix2.data[0][0], Cell(string_data2[0].clone()));
assert_eq!(string_matrix2.data[0][1], Cell(string_data2[1].clone()));
assert_eq!(string_matrix2.data[1][0], Cell(string_data2[2].clone()));
assert_eq!(string_matrix2.data[1][1], Cell(string_data2[3].clone()));
}
#[test]
fn test_int_by_row() {
let int_data: [i32; 4] = [-1, 0,
4, 12];
let int_matrix = Matrix::new(&int_data);
let by_row = int_matrix.by_row();
assert_eq!(by_row[0], Cell(int_data[0]));
assert_eq!(by_row[1], Cell(int_data[1]));
assert_eq!(by_row[2], Cell(int_data[2]));
assert_eq!(by_row[3], Cell(int_data[3]));
let int_data2: [i32; 4] = [123, 5,
-1234, 142];
let int_matrix2 = Matrix::new(&int_data2);
let by_row2 = int_matrix2.by_row();
assert_eq!(by_row2[0], Cell(int_data2[0]));
assert_eq!(by_row2[1], Cell(int_data2[1]));
assert_eq!(by_row2[2], Cell(int_data2[2]));
assert_eq!(by_row2[3], Cell(int_data2[3]));
}
#[test]
fn test_string_by_row() {
let string_data: [String; 4] = [String::from(""), String::from("12"),
String::from("fasfasfwe"), String::from("^%&#$%SDF")];
let string_matrix = Matrix::new(&string_data);
let by_row = string_matrix.by_row();
assert_eq!(by_row[0], Cell(string_data[0].clone()));
assert_eq!(by_row[1], Cell(string_data[1].clone()));
assert_eq!(by_row[2], Cell(string_data[2].clone()));
assert_eq!(by_row[3], Cell(string_data[3].clone()));
let string_data2: [String; 4] = [String::from(" "), String::from("1 3"),
String::from("АСДгфдмирер"), String::from("@АС%$№СДФ^&")];
let string_matrix2 = Matrix::new(&string_data2);
let by_row2 = string_matrix2.by_row();
assert_eq!(by_row2[0], Cell(string_data2[0].clone()));
assert_eq!(by_row2[1], Cell(string_data2[1].clone()));
assert_eq!(by_row2[2], Cell(string_data2[2].clone()));
assert_eq!(by_row2[3], Cell(string_data2[3].clone()));
}
#[test]
fn test_int_by_col() {
let int_data: [i32; 4] = [-1, 0,
4, 12];
let int_matrix = Matrix::new(&int_data);
let by_col = int_matrix.by_col();
assert_eq!(by_col[0], Cell(int_data[0]));
assert_eq!(by_col[1], Cell(int_data[2]));
assert_eq!(by_col[2], Cell(int_data[1]));
assert_eq!(by_col[3], Cell(int_data[3]));
let int_data2: [i32; 4] = [123, 5,
-1234, 142];
let int_matrix2 = Matrix::new(&int_data2);
let by_col2 = int_matrix2.by_col();
assert_eq!(by_col2[0], Cell(int_data2[0]));
assert_eq!(by_col2[1], Cell(int_data2[2]));
assert_eq!(by_col2[2], Cell(int_data2[1]));
assert_eq!(by_col2[3], Cell(int_data2[3]));
}
#[test]
fn test_string_by_col() {
let string_data: [String; 4] = [String::from(""), String::from("12"),
String::from("fasfasfwe"), String::from("^%&#$%SDF")];
let string_matrix = Matrix::new(&string_data);
let by_col = string_matrix.by_col();
assert_eq!(by_col[0], Cell(string_data[0].clone()));
assert_eq!(by_col[1], Cell(string_data[2].clone()));
assert_eq!(by_col[2], Cell(string_data[1].clone()));
assert_eq!(by_col[3], Cell(string_data[3].clone()));
let string_data2: [String; 4] = [String::from(" "), String::from("1 3"),
String::from("АСДгфдмирер"), String::from("@АС%$№СДФ^&")];
let string_matrix2 = Matrix::new(&string_data2);
let by_col2 = string_matrix2.by_col();
assert_eq!(by_col2[0], Cell(string_data2[0].clone()));
assert_eq!(by_col2[1], Cell(string_data2[2].clone()));
assert_eq!(by_col2[2], Cell(string_data2[1].clone()));
assert_eq!(by_col2[3], Cell(string_data2[3].clone()));
}
#[test]
fn test_add() {
let int_data: [i32; 4] = [-1, 0,
4, 12];
let int_matrix = Matrix::new(&int_data);
let string_data: [String; 4] = [String::from(""), String::from("12"),
String::from("fasfasfwe"), String::from("^%&#$%SDF")];
let string_matrix = Matrix::new(&string_data);
assert_eq!(
(int_matrix + string_matrix).by_row(),
string_cell_vec(" 1", "0 12", "4 fasfasfwe", "12 ^%&#$%SDF")
);
let int_data2: [i32; 4] = [123, 5,
-1234, 142];
let int_matrix2 = Matrix::new(&int_data2);
let string_data2: [String; 4] = [String::from(" "), String::from("1 3"),
String::from("АСДгфдмирер"), String::from("@АС%$№СДФ^&")];
let string_matrix2 = Matrix::new(&string_data2);
assert_eq!(
(int_matrix2 + string_matrix2).by_row(),
string_cell_vec("123 ", "5 1 3", "реримдфгДСА 1234", "142 @АС%$№СДФ^&")
);
}
#[test]
fn test_mul() {
let int_data: [i32; 4] = [-1, 0,
4, 12];
let int_matrix = Matrix::new(&int_data);
let string_data: [String; 4] = [String::from(""), String::from("12"),
String::from("fasfasfwe"), String::from("^%&#$%SDF")];
let string_matrix = Matrix::new(&string_data);
assert_eq!(
(int_matrix * string_matrix),
String::from(" 12121212 ^%&#$%SDF^%&#$%SDF^%&#$%SDF^%&#$%SDF^%&#$%SDF^%&#$%SDF^%&#$%SDF^%&#$%SDF^%&#$%SDF^%&#$%SDF^%&#$%SDF^%&#$%SDF")
);
let int_data2: [i32; 4] = [3, 5,
-14, 2];
let int_matrix2 = Matrix::new(&int_data2);
let string_data2: [String; 4] = [String::from(" "), String::from("1 3"),
String::from("АСДгфдмирер"), String::from("@АС%$№СДФ^&")];
let string_matrix2 = Matrix::new(&string_data2);
assert_eq!(
(int_matrix2 * string_matrix2),
String::from(" АСДгфдмирерАСДгфдмирерАСДгфдмирерАСДгфдмирерАСДгфдмирер 3 13 13 13 13 13 13 13 13 13 13 13 13 13 1 @АС%$№СДФ^&@АС%$№СДФ^&")
);
}
}
}

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

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

running 15 tests
test solution_test::test_adding_int_and_string_negative ... ok
test solution_test::test_adding_int_and_string_positive ... ok
test solution_test::test_adding_int_and_string_unicode ... ok
test solution_test::test_adding_int_and_string_zero ... ok
test solution_test::test_adding_matrices_1 ... ok
test solution_test::test_adding_matrices_2 ... ok
test solution_test::test_blank_strings ... ok
test solution_test::test_iterating_i32s ... ok
test solution_test::test_iterating_strings ... ok
test solution_test::test_multiplying_int_and_string_negative ... ok
test solution_test::test_multiplying_int_and_string_positive ... ok
test solution_test::test_multiplying_int_and_string_unicode ... ok
test solution_test::test_multiplying_int_and_string_zero ... ok
test solution_test::test_multiplying_matrices_1 ... ok
test solution_test::test_multiplying_matrices_2 ... ok

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

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

Ростислав качи първо решение на 13.11.2021 02:32 (преди почти 4 години)

Когато пишеш тестове, добра идея е те да бъдат лесни за валидация на ръка. Ако имаш тест, който проверява, че баба се обръща до абаб, много лесно се вижда какво се очаква като вход и като изход, в сравнение със ^%&#$%SDF. Повечето от тестовите ти данни са доста хаотични -- това не е полезно. За кода няма значение дали си написал asdfsafjlkjslkjf или четима дума, но за хората, които четат, определено има.

Същото се отнася за писането на код в тестове. Отне ми известно време ментално за изпарся:

let mut expected = "явекявекоас".chars().rev().collect::<String>();
expected.push_str(" 5");
assert_eq!((Cell(-5) + Cell(String::from("явекявекоас"))).0, expected);

Чакай, входа е явекявекоас, изхода също? Но не, всъщност expected обръща този низ. Добре де, тогава защо не го обърна на ръка?

let mut expected = String::from("саокевякевя 5");
assert_eq!((Cell(-5) + Cell(String::from("явекявекоас"))).0, expected);

Входа е статичен -- не е полезно да го генерираш динамично за самия тест, и не е удобно откъм четимост. Донякъде може би проблема е свързан точно с това колко е хаотичен низа -- трудно е ментално да се обърне (аз го пуснах в irb за да го обърна).

Няма голямо значение и колко е дълъг низа -- няма различен handling за дълги и кратки низове.

Basically, покрил си доста случаи, включително unicode, и това е супер, но е добра идея да се постараеш тестовете ти да са по-прости :). Не само ще улесниш живота на хора, които ги четат, но и намаляваш броя на неща, които могат да се объркат -- ако изпуснеш .rev() и в кода, и в тестовете, всичко ще си минава. Сравнително малко вероятно е, но няма как да допуснеш такава грешка ако имаш сравнение между баба и абаб (примерно).