3rd exercise from chapter 8 of the book

Exercise 3:

Using a hash map and vectors, create a text interface to allow a user to add employee names to a department in a company. For example, “Add Sally to Engineering” or “Add Amir to Sales.” Then let the user retrieve a list of all people in a department or all people in the company by department, sorted alphabetically

I know there's tons of these types of questions, so thank you for clicking on this one haha. I think I made to sure to handle all edge cases, but please let me know if there's anything I might've missed. Also, any other ways of solving this exercise or making it more efficient is welcome too. Thank you!

use std::{
    collections::HashMap,
    io::{self, Write},
};

fn main() {
    println!("Welcome to AdminCLI. Do administrative things for a totally real company!");

    let mut company: HashMap<String, Vec<String>> = HashMap::new();
    let mut input = String::new();

    loop {
        println!("\n\nAvailable commands:\n\t- 'Add <Name> to <Department>' to do exactly that\n\t- 'List <department>` to list every employee in the company in a tree-like structure\n\t- 'List all' to list every employee within this department\n\t- 'Exit' to stop AdminCLI\n");
        print!("Enter command: ");
        input.clear();
        io::stdout().flush().unwrap();
        io::stdin()
            .read_line(&mut input)
            .expect("\nerror: unable to read your input");
        let words: Vec<&str> = input.trim().split(' ').collect();
        match words.as_slice() {
            ["Add", name, "to", dept] => company
                .entry(dept.to_string())
                .or_default()
                .push(name.to_string()),
            ["List", "all"] => {
                for (dept, names) in &company {
                    println!("\n[{}]", dept);
                    for name in names {
                        println!("    {}", name);
                    }
                }
            }
            ["List", dept] => match company.get(*dept) {
                Some(names) => {
                    println!("\n[{}]", dept);
                    for name in names {
                        println!("    {}", name);
                    }
                }
                None => {
                    println!("\n'{}' department not found", dept);
                    continue;
                }
            },
            ["Exit"] => {
                println!("\nAdminCLI stopped ... Have a nice day\n");
                break;
            }
            _ => println!("\nunknown command, use only the defined commands"),
        }
    }
}

Looks good! A couple quick comments.

You forgot the "sorted alphabetically" part.

It would be more readable to split the long string literals on multiple lines with backslashes.

1 Like

Sweet, thanks.

I completely overlooked that part hahaha

I actually tried that, but the output looked weird because it included the indentation. How do I split it up for readability while not included the indentations?

You're welcome!

All white space is removed between the backslash at the end of one line, and the first non-white space char on the next line. So you can indent the next line as usual. For example:

        println!(
            "\n\nAvailable commands:\n\
            \t- 'Add <Name> to <Department>' to do exactly that\n\
            \t- 'List <department>` to list every employee in the company in a \
            tree-like structure\n\
            \t- 'List all' to list every employee within this department\n\
            \t- 'Exit' to stop AdminCLI\n"
        );
3 Likes

You can also move the string to a top-level constant so that you don't need indentation or escapes (yes, r#""# is unnecessary here, but I always use it on multi-line strings just to avoid having to think about whether it is necessary or not and to protect against future edits):

const HELP_MESSAGE: &str = r#"
Available commands:
  - 'Add <Name> to <Department>' to do exactly that
  - 'List <department>` to list every employee in the company in a tree-like structure
  - 'List all' to list every employee within this department
  - 'Exit' to stop AdminCLI
"#;

fn main() {
    ...
    println!("{}", HELP_MESSAGE);
    ...
}
4 Likes

Yeah I think I prefer making it a top-level constant. I feel like if I were to have other people working on this code, it would make more sense to make it into a constant. Thank you so much, that's really helpful!

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.