Either sort or retrieve a sorted list from a vector or a HashMap value alphabetically

#1

I’m working my way through The Book and doing the last exercise under HashMap. The last exercise has really challenged me. https://doc.rust-lang.org/book/ch08-03-hash-maps.html#summary

I can’t seem to find a way to sort or retrieve the company directory alphabetically. Here is the code that I’ve worked out, I’m limited to using the standard library and what The Book has taught me thus far. It looks like there are some crates out there, but I don’t think I’m supposed to use them to learn how to do this:

/*
    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.
    */

    let mut names = Vec::new();
    let mut departments = Vec::new();
    let mut directory = HashMap::new();

    loop {
        println!("Here are the departments in our company {:?}", departments);
        println!("Do you want to add another [p]erson, view by [d]epartment, view [a]ll or [q]uit");
        let mut yn = String::new(); //we put it hear so it clears at each loop
        io::stdin().read_line(&mut yn).expect("failed to read line");
        match yn.trim() {
            "p" => {
                let mut name = String::new();
                let mut department = String::new();
                println!("Input first and last name");
                io::stdin()
                    .read_line(&mut name)
                    .expect("failed to read line");

                println!("What department does {} work in?", name);
                io::stdin()
                    .read_line(&mut department)
                    .expect("failed to read line");

                departments.push(department.trim().to_string());
                names.push(name.trim().to_string());

                directory
                    .entry(department.trim().to_string())
                    .or_insert_with(Vec::new)
                    .push(name.trim().to_string());
            }
            "d" => {
                println!(
                    "Which department would you like to see?"
                );
                let mut x = String::new();
                io::stdin()
                    .read_line(&mut x)
                    .expect("failed to read line");
                println!("These people work in {:?}: {:?}", &x.trim().to_string(), directory.get(&x.trim().to_string()));

            }
            "a" => {
                println!(
                    "These are all the people in our company {:?}.",
                    names
                );
            }
            "q" => break,
            _ => {
                println!("you typed {}", yn);
            }
        }
    }
#2

Two questions:

  1. Are you allowed to use your own created code from the standard library (I.E. devising an algorithm)
  2. Have you learned about iterators yet (And how to make them) because that’d be a nice way to implement it (as in a challenge)
1 Like
#3

Yeah, as you suspect, you’re keeping parallel data structures unnecessarily. Look at ways of getting the data on demand out of the hashmap you already have, even if you have to do manipulations (like sorting) on a temporary copy. And yes, this will involve iterators.

spoiler

HashMap can enumerate its values… Iterator can flatten nested list-of-lists structure and collect results… A slice of a vector can be sorted in-place…

1 Like
#4
  1. Yes, I can create my own code in blocks but truth be told I’m just an artist with some experience in processing and django. This is a brave new world. Willing to try though.

  2. I have not learned how to make iterators, at least I don’t think so. Will take a look.

#5

OK, so it seems like you are both pointing me towards making my own iterator. I don’t know what you mean by keeping parallel data structures…I’ll have to read up on that and study my code.

#6

No, to be clear just in case you read it this way, I’m not suggesting you need to make your own struct with impl Iterator for Foo. You just need to use some the iterators produced by the data structures you already have (HashMap) and some of the iterator methods to combine and manipulate them.

By parallel data structures, I just mean several structures holding the same data. For example, in your code above, you’re inserting user input into several things

There’s redundancy here, which (in general, when scaling up) means storage overhead and potential for bugs keeping them in sync.

What I was suggesting was that you keep the data in one structure, and figure out how to query that structure for the elements you need. For example, I can get the list of departments by asking the directory for its keys, rather than keeping it separately.

1 Like
#7

OK, thanks for the clarification. I was going to try and do exactly what you described. Will work on this later and post back results.