Rust HashMaps

What is a HashMap in Rust?

A HashMap is part of the std: :collections module and is represented as HashMap<K, V>, where:

  • K is the type of keys.
  • V is the type of values.

Each key must be unique, and values are accessed using their corresponding keys.

Why Use a HashMap?

  1. Key-Value Pair Storage: Ideal for mapping data relationships, such as storing a student’s name and their grades.
  2. Fast Access: Lookups and updates are fast due to the underlying hash function.
  3. Flexible Keys and Values: Supports custom types for keys and values.

Creating a HashMap

To use HashMaps, you need to include the std: :collections module.

1. Using HashMap: :new

You can create an empty HashMap and add entries later.

use std::collections::HashMap;

fn main() {
let mut scores = HashMap::new();
scores.insert("Alice", 90);
scores.insert("Bob", 80);

println!("{:?}", scores); // Output: {"Alice": 90, "Bob": 80}
}

2. Using the from Method

You can initialize a HashMap with predefined values.

use std::collections::HashMap;

fn main() {
let scores: HashMap<&str, i32> = [("Alice", 90), ("Bob", 80)].into_iter().collect();
println!("{:?}", scores); // Output: {"Alice": 90, "Bob": 80}
}

Accessing Values in a HashMap

To access a value, use the key. The .get() method returns an Option<&V>.

Example: Accessing a Value

use std::collections::HashMap;

fn main() {
let mut scores = HashMap::new();
scores.insert("Alice", 90);

match scores.get("Alice") {
Some(&score) => println!("Alice's score is {}", score), // Output: Alice's score is 90
None => println!("No score found for Alice"),
}
}

Direct Indexing

You can use square brackets, but this will panic if the key is not found.

fn main() {
let mut scores = HashMap::new();
scores.insert("Alice", 90);

println!("{}", scores["Alice"]); // Output: 90
}

Modifying a HashMap

You can modify values or add/remove entries in a HashMap.

1. Adding or Updating a Value

Use .insert() to add a new key-value pair or update an existing value.

use std::collections::HashMap;

fn main() {
let mut scores = HashMap::new();
scores.insert("Alice", 90);
scores.insert("Alice", 95); // Updates the value

println!("{:?}", scores); // Output: {"Alice": 95}
}

2. Updating Only if Key Exists

Use .entry() with .or_insert() to modify values conditionally.

use std::collections::HashMap;

fn main() {
let mut scores = HashMap::new();
scores.insert("Alice", 90);

scores.entry("Alice").or_insert(95); // Won't update as "Alice" exists
scores.entry("Bob").or_insert(85); // Adds "Bob"

println!("{:?}", scores); // Output: {"Alice": 90, "Bob": 85}
}

3. Removing a Key

Use .remove() to delete a key-value pair.

use std::collections::HashMap;

fn main() {
let mut scores = HashMap::new();
scores.insert("Alice", 90);
scores.remove("Alice");

println!("{:?}", scores); // Output: {}
}

Iterating Over a HashMap

You can loop through a HashMap using .iter().

Example: Iterating Over Key-Value Pairs

use std::collections::HashMap;

fn main() {
let mut scores = HashMap::new();
scores.insert("Alice", 90);
scores.insert("Bob", 80);

for (key, value) in &scores {
println!("{}: {}", key, value);
}
// Output:
// Alice: 90
// Bob: 80
}

Ownership and HashMaps

Keys and values are moved into the HashMap unless they implement the Copy trait. To retain ownership, use references.

Example: Using References

use std::collections::HashMap;

fn main() {
let name = String::from("Alice");
let mut scores = HashMap::new();
scores.insert(&name, 90); // Use reference to avoid moving `name`

println!("{:?}", scores); // Output: {"Alice": 90}
}

HashMap Operations

1. Checking Key Existence

Use .contains_key() to verify if a key exists.

fn main() {
let mut scores = HashMap::new();
scores.insert("Alice", 90);

println!("{}", scores.contains_key("Alice")); // Output: true
}

2. Clearing a HashMap

Use .clear() to remove all entries.

fn main() {
let mut scores = HashMap::new();
scores.insert("Alice", 90);
scores.clear();

println!("{:?}", scores); // Output: {}
}

3. Merging HashMaps

Combine two HashMaps using .extend().

use std::collections::HashMap;

fn main() {
let mut scores1 = HashMap::new();
scores1.insert("Alice", 90);

let mut scores2 = HashMap::new();
scores2.insert("Bob", 80);

scores1.extend(scores2);

println!("{:?}", scores1); // Output: {"Alice": 90, "Bob": 80}
}

Performance Considerations

  1. Hash Function: The default hash function is designed for speed and security but can be replaced with a custom one.
  2. Memory Usage: HashMaps consume more memory compared to arrays or vectors due to internal hashing and resizing mechanisms.
  3. Pre-Allocation: Use .with_capacity() to initialize a HashMap with a predefined size.

Leave a Comment

BoxofLearn