XenatoniT
@XenatoniT
Увлекаюсь программированием.

Правильно ли решил задачу?

начал изучать язык программирования "rust", нашел задание в книге. Но, такое чувство, что можно сделать по другому и лучше.
Условие задачи
Распечатать текст рождественской песни "двенадцать дней рождества", воспользовавшись повторами в песне.

fn main() {
    another_function();
}

fn another_function() {
    let mut text1:String = String::from("
    On the first day of Christmas
    My true love sent to me
    ");
    let text2: String = String::from("A partridge in a pear tree");

    if true {
        println!("{text1}{text2}");
        text1 += "Two turtle-doves";
        println!("{text1}\n    {text2}");
        text1 += "\n    Three French hens";
        println!("{text1}\n    {text2}");
        text1 += "\n    Four calling birds";
        println!("{text1}\n    {text2}");
        text1 += "\n    Five golden rings (five golden rings)";
        println!("{text1}\n    {text2}");
        text1 += "\n    Six geese a laying";
        println!("{text1}\n    {text2}");
        text1 += "\n    Seven swans a swimming";
        println!("{text1}\n    {text2}");
        text1 += "\n    Eight maids a milking";
        println!("{text1}\n    {text2}");
        text1 += "\n    Nine ladies dancing";
        println!("{text1}\n    {text2}");
        text1 += "\n    Ten lords a-leaping";
        println!("{text1}\n    {text2}");
        text1 += "\n    I sent 11 pipers piping";
        println!("{text1}\n    {text2}");
        text1 += "\n    12 drummers drumming";
        println!("{text1}\n    {text2}\n    And a partridge in a pear tree");
        
    }
}


Текст песни
https://www.google.com/search?q=12+%D0%B4%D0%BD%D0...)

On the first day of Christmas
My true love sent to me
A partridge in a pear tree
On the second day of Christmas
My true love sent to me
Two turtle-doves
And a partridge in a pear tree
On the third day of Christmas
My true love sent to me
Three French hens
Two turtle-doves
And a partridge in a pear tree
On the fourth day of Christmas
My true love sent to me
Four calling birds
Three French hens
Two turtle-doves
And a partridge in a pear tree
On the fifth day of Christmas
My true love sent to me
Five golden rings (five golden rings)
Four calling birds
Three French hens
Two turtle-doves
And a partridge in a pear tree
On the sixth day of Christmas
My true love sent to me
Six geese a laying
Five golden rings (five golden rings)
Four calling birds
Three French hens
Two turtle-doves
And a partridge in a pear tree
On the seventh day of Christmas
My true love sent to me
Seven swans a swimming
Six geese a-laying
Five golden rings (five golden rings)
Four calling birds
Three French hens
Two turtle-doves
And a partridge in a pear tree
On the eighth day of Christmas
My true love sent to me
Eight maids a milking
Seven swans a swimming
Six geese a-laying
Five golden rings (five golden rings)
Four calling birds
Three French hens
Two turtle-doves
And a partridge in a pear tree
On the ninth day of Christmas
My true love sent to me
Nine ladies dancing
Eight maids a-milking
Seven swans a-swimming
Six geese a-laying
Five golden rings (five golden rings)
Four calling birds
Three French hens
Two turtle-doves
And a partridge in a pear tree
On the tenth day of Christmas
My true love sent to me
Ten lords a-leaping
Nine ladies dancing
Eight maids a-milking
Seven swans a-swimming
Six geese a-laying
Five golden rings (five golden rings)
Four calling birds
Three French hens
Two turtle-doves
And a partridge in a pear tree
On the 11th day of Christmas
My true love sent to me
I sent 11 pipers piping
Ten lords a-leaping
Nine ladies dancing
Eight maids a-milking
Seven swans a-swimming
Six geese a-laying
Five golden rings (five golden rings)
Four calling birds
Three French hens
Two turtle-doves
And a partridge in a pear tree
On the 12th day of Christmas
My true love sent to me
12 drummers drumming
Eleven pipers piping
Ten lords a-leaping
Nine ladies dancing
Eight maids a-milking
Seven swans a-swimming
Six geese a-laying
Five golden rings (five golden rings)
Four calling birds
Three French hens
Two turtle-doves
And a partridge in a pear tree
And a partridge in a pear tree
  • Вопрос задан
  • 247 просмотров
Решения вопроса 1
mayton2019
@mayton2019
Bigdata Engineer
Можно сделать коллекцию из этих строк
"Two turtle-doves", "Three French hens"
тогда алгоритм упрощается. Визуальная копи-паста уходит.
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
bingo347
@bingo347
Crazy on performance...
Задачка прикольная для обучения, позволяет поработать сразу со многими конструкциями языка.

Для начала комментарии по Вашему решению:
1. Тип String алоцирует память на куче, операция += над типом String может приводить к реалокации памяти. Алокация памяти не дешевая операция, в данной задаче можно обойтись вообще без нее.
2. Для повторяющихся операций придумали циклы, а с циклами хорошо сочетаются коллекции, например массивы и слайсы.
3. Уже писали в комментах, но все же, if true - бесполезная штука.

Теперь давайте посмотрим на текст песни. У нас 12 куплетов.
Каждый куплет начинается с очень похожих строчек: "On the first day of Christmas", "On the second day of Christmas", и т.д., меняется только числительное.
Потом всегда идет строчка "My true love sent to me" в каждом куплете.
Затем идет от 1 до 12 строчек, повторяющиеся из куплета в куплет, но в i-том куплете будет только i таких строчек. Притом тут есть особенность, что первая строчка в куплете иногда отличается от своих аналогов в последующих куплетах.
Ну и наконец, в 12 куплете мы видим, что строка "And a partridge in a pear tree" присутствует 2 раза, что выбивается из общего правила.

Решение с объяснением

Для начала вынесем факт того, что у нас 12 куплетов в константу, это нам пригодится для дальнейшего объявления массивов и итерации по ним.
const NUMBER_OF_VERSES: usize = 12;

Заведем массив числительных, которые меняются в первых строчках куплетов.
const NUMERALS: [&str; NUMBER_OF_VERSES] = [
    "first", "second", "third", "fourth", "fifth", "sixth", "seventh", "eighth", "ninth", "tenth",
    "11th", "12th",
];


Так же заведем массив, для повторяющихся строчек куплетов.
const LINES: [&str; NUMBER_OF_VERSES] = [
    "And a partridge in a pear tree",
    "Two turtle-doves",
    "Three French hens",
    "Four calling birds",
    "Five golden rings (five golden rings)",
    "Six geese a-laying",
    "Seven swans a-swimming",
    "Eight maids a-milking",
    "Nine ladies dancing",
    "Ten lords a-leaping",
    "Eleven pipers piping",
    "12 drummers drumming",
];


Так же нам понадобится массив первых строчек куплетов, так как среди них есть отличающиеся. Я нашел такие в 1 и 11 куплете (так как массивы у нас индексируются с 0, то они будут под индексами 0 и 10 соответственно). Остальные же будут такими же как в массиве LINES, а значит можно по экономить размер бинаря и занимаемую память за счет того что в массивах у нас только ссылки на строки, которые можно копировать.
Тут конечно можно написать что-то вроде
const DIFFERING_LINES: [&str; NUMBER_OF_VERSES] = [
    "A partridge in a pear tree",
    LINES[1],
    LINES[2],
    // ...
];
но это дикая копипаста, которая плохо читается и подвержена ошибкам.
Благо в Rust есть константные функции, которые могут выполняться в compile-time и возвращают константы, а значит можно наш константный массив сгенерировать. Правда константные функции довольно сильно ограничены, в них можно пользоваться лишь ветвлениями, циклами, простейшей арифметикой (в том числе над указателями, а значит и получать доступ к элементам массива по индексу). Так же можно вызывать другие константные функции. Цикл for нам к сожалению тут не доступен, так как он работает поверх итераторов, а методы IntoIter::into_iter и Iterator::next, которые он вызывает, не являются константными. Но цикл со счетчиком можно сделать и через while. По итогу получим такую функцию:
const fn gen_differing_lines() -> [&'static str; NUMBER_OF_VERSES] {
    let mut i = 0;
    let mut lines = [""; NUMBER_OF_VERSES];
    while i < NUMBER_OF_VERSES {
        lines[i] = match i {
            0 => "A partridge in a pear tree",
            10 => "I sent 11 pipers piping",
            i => LINES[i],
        };
        i += 1;
    }
    lines
}

И инициализируем ей наш массив:
const DIFFERING_LINES: [&str; NUMBER_OF_VERSES] = gen_differing_lines();


Теперь еще особенность, в самих куплетах, строчки из LINES в них идут в обратном порядке. То есть для 4 куплета (индекс 3) нам помимо строчки DIFFERING_LINES[3] нам нужно напечатать строки под индексами 2, 1 и 0 из LINES. Для удобства вынесем печать строк из LINES в отдельную функцию:
fn print_verse(mut i: usize) {
    while i > 0 {
        i -= 1;
        println!("{}", LINES[i]);
    }
}


Ну и осталось написать основной код для печати:
fn main() {
    for i in 0..NUMBER_OF_VERSES {
        println!("On the {} day of Christmas", NUMERALS[i]);
        println!("My true love sent to me");
        println!("{}", DIFFERING_LINES[i]);
        print_verse(i);
    }
    println!("{}", LINES[0]);
}


А полное решение можно посмотреть и запустить тут:
https://play.rust-lang.org/?version=stable&mode=re...
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы