Closer Scrutiny of Rust Collections [Part-2]

Reading Time: 4 minutes

The Collections are the general-purpose programming data structures provided by Rust’s Standard library. Rust can provide many cool implementations of data structures like Vector, Linked list, Hash map, BTreeMap, etc.

This image has an empty alt attribute; its file name is rust-2-wal.png

Hello, folks!  your wait is over, here is the second blog of Closer Scrutiny of Rust Collections. I hope you have learned a lot from the first part. It’s better to go with the previous blog first to gain more understanding about Collections.
We have categorised the Rust collections into three groups:

  • Sequences.
  • Map.
  • Sets.

The Sequence category, we already discussed in our previous blog. Now, we will understand the Collections comes under the category Maps.

HashMap

The HashMap is a collection of key-value pairs. A HashMap stores the keys and values in a hash table. The key is used to search for values in the HashMap.
The keys in HashMap are ordered in a randomised manner. Which makes the tables more resistant to denial-of-service(DOS) attacks. The HashMap structure is defined in the std::collections module.

Points to remember:

  • HashMap contains values based on the key.
  • HashMap contains only unique keys.
  • The static method new() is used to create a HashMap object.
  • We can use HashMap when we want to associate arbitrary keys with an arbitrary value.
  • We can do many operations on HashMap like insert, get, length of HashMap, contain_key, remove, etc.

Let’s understand more with the help of an example:

use std::collections::HashMap;

fn main(){
    // Initialise the HashMap
   let mut inventions = HashMap::new();
   
   // Insert some values to the HashMap
   inventions.insert("Electric Battery", "1800");
   inventions.insert("Computer", "1822");
   inventions.insert("Electric Bulb", "1880");
   
   // Print the size of HashMap
   println!("Size of HashMap: {}", inventions.len());
   
   // Contains operation
   if inventions.contains_key(&("Computer")){
       println!("Computer is present in the HashMap");
   }
   
   // Get the value from the HashMap
   match inventions.get("Electric Bulb") {
        Some(value) => println!("Electric Bulb is invented in {}\n", value),
        None => println!("Not found.")
    }
   
   // Print all the values from the HashMap
   for (invention, year) in inventions {
        println!("{} is invented in {}.", invention, year);
    }
}

Output:

This image has an empty alt attribute; its file name is screenshot-from-2019-11-14-12-35-28.png

In this example, we have initialised the HashMap and insert some values to the HashMap. Then check whether the given value is in the HashMap or not, after that print all the values from the HashMap.

BTreeMap:

The BTreeMap is the map-based data structure of B-Tree. BTreeMap is more compact in memory and iteration is deterministic on the content of the map.
BTreeMap also has better cache coherency which means iteration through the elements can be faster. Cache hits save a tremendous amount of time. The implementation of BTreeMap simply performs a naive linear search. This provides excellent performance on small nodes of elements which are cheap to compare.

When we should use BTreeMap:

  • You want a map sorted by its keys.
  • Need excellent performance.
  • You want to be able to get all of the entries in order on-demand.
  • You want to find the largest or smallest key that is smaller or larger than something.


Let’s understand more with the help of an example:

use std::collections::BTreeMap;

fn main () {
    // Initialising the BTreeMap
    let mut languages = BTreeMap::new();
    
    // Insert values to the BTreeMap
    languages.insert("Python", 1989);
    languages.insert("Scala", 2003);
    languages.insert("Rust", 2015);
    
    // Check whether the given value exist in the BTreeMap or not
    assert_eq!(languages.contains_key(&"Rust"), true);
    
    // Fetch the value from the respective key
    match languages.get_mut(&"Rust") {
        Some(value) => println!("Rust is founded in {}.", value),
        None => ()
    }
    
    // Check whether the BTreeMap is empty or not
    assert!(!languages.is_empty());
    
    // Remove a value from the BTreeMap from the key
    assert_eq!(languages.remove(&"Scala"), Some(2003));
    
    // Print all the value of BTreeMap
    for (key, value) in languages {
        println!("{}: {}", key, value);
    }
}

Output:

This image has an empty alt attribute; its file name is screenshot-from-2019-11-09-16-43-15.png

In this example, we have initialised the BTreeMap and Insert some values to the BTreeMap. Then check whether the given value is in the BTreeMap or not, after that, we have fetched value from the BTreeMap by its respective key. Then we have checked whether the BTreeMap is empty or not.
After that, we have removed a value from the BTreeMap. At last, we have printed all the values from the BTreeMap.

Performance:

Here is the performance comparison chart of different operations on the Collections which comes under Maps.

Note: This is the second part of the series of blogs on Collections, I’ll post next blog soon. Stay Tuned.

Thanks for reading the blog!

This image has an empty alt attribute; its file name is footer-2.jpg

Written by 

Pankaj Chaudhary is a Software Consultant at Knoldus LLP. He has 1.5+ years of experience with good knowledge of Rust, Python, Java, and C. Now he is working as Rust developer and also works on machine learning and data analysis because he loves to play with data and extract some useful information from it. His hobbies are bike riding and explore new places.