Word Frequency Analyzer in Rust and Python

Count word frequencies using HashMaps in Rust and dictionaries in Python.

Introduction

30 Second Summary

Think about how a search engine knows which pages are most relevant to your query. Behind the scenes, it counts how often words appear and ranks results accordingly. That core counting technique is powered by a data structure called a hashmap.

In this project, you will build a command-line Word Frequency Analyzer twice: once in Python using a dictionary, and once in Rust using a HashMap. By building the same tool in both languages, you will see exactly how each one handles counting and grouping data.

What You'll Build

A CLI tool that reads a text string, counts how many times each word appears, and displays the results sorted by frequency.

By the end of this project, you'll have:

  • A Python script (word_freq.py) that counts and displays word frequencies using a dictionary.
  • A Rust binary (word_freq) that solves the same problem using HashMap and Rust's ownership patterns.
  • A side-by-side understanding of how both languages handle key-value data structures.
  • Secret Mission: Extend both programs to read from files and display visual bar charts in the terminal.

Are there any prerequisites?

You should have a basic understanding of variables, functions, and loops in at least one programming language. No prior Rust or Python experience is required.

Before We Start

You are about to build a Word Frequency Analyzer in two languages: Python and Rust. Before writing any code, you need the right tools installed and ready to go.

In this step, you will install the Rust compiler, confirm Python is available, and create the project folders for both implementations.

In this step, get ready to:
  • Install and verify Rust.
  • Verify Python 3 is ready.
  • Create both project directories.
Install Rust via rustup

Rust is installed and managed through a tool called rustup. It handles downloading the compiler, the package manager (cargo), and keeping everything up to date.

  • Press Cmd+Space (macOS) or the Windows key (Windows) to open your search bar.
  • Type Terminal and press Enter to open it.
  • Install Rust by running the command for your operating system:

macOS

  • Run the official rustup installer by pasting this command:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

What does this command do?

This downloads a script from the official Rust website and runs the installer. It sets up rustc (the compiler), cargo (the package manager), and adds them to your PATH.

The installer will display three options. Press 1 then Enter to proceed with the standard installation.

After installation completes, close and reopen your terminal so the PATH changes take effect.

Windows

  • Visit https://www.rust-lang.org/tools/install in your browser.
  • Download and run rustup-init.exe.
  • You may be prompted to install Visual Studio C++ Build Tools. Allow this if prompted.
  • When you see the installation options, press 1 then Enter to proceed with the standard installation.
  • After installation completes, close and reopen your terminal.

Why do I need Visual Studio Build Tools?

Rust on Windows needs a linker to combine compiled outputs into a final executable. The Visual Studio C++ Build Tools provide this linker.

  • Verify Rust installed correctly by running:
rustc --version

✔️ I see a version number

You should see something like rustc 1.x.x. Rust is ready to go.

ⓧ Command not found

Your terminal does not know where rustc is. This usually means the PATH was not updated.

  • Close your terminal completely and reopen it.
  • Run rustc --version again.
  • If it still fails on macOS, run the following to manually update your PATH:
. "$HOME/.cargo/env"

Then try rustc --version one more time. On Windows, restarting your terminal is usually sufficient.

Verify Python 3 is installed

Python is likely already on your machine. Let's confirm it is available and ready.

  • Check your Python version by running:
python3 --version

✔️ I see a version number

You should see something like Python 3.x.x. Python is ready.

ⓧ Command not found

Python 3 is not installed or not in your PATH.

  • Visit https://www.python.org/downloads and download the latest Python 3 installer for your operating system.
  • Run the installer. On Windows, check the box that says Add Python to PATH before clicking Install Now.
  • Close and reopen your terminal after installing.
  • Run python3 --version again to confirm.
Create the project directories

You will keep the Python and Rust versions of your analyzer in separate folders on your Desktop.

  • Move to your Desktop by running this command:
cd ~/Desktop
  • Create the Python project folder by running:
mkdir word-freq-python
  • Create the Rust project using cargo by running:
cargo new word-freq-rust

What does cargo new do?

The cargo new command creates a new Rust project with a standard folder structure. It generates a Cargo.toml file (project configuration) and a src/main.rs file with a starter Hello World program.

  • Confirm both project folders exist by running:
ls

You should see both word-freq-python and word-freq-rust in the output.

Don't see both folders?

Make sure you ran cd ~/Desktop first. If cargo new failed, check that Rust installed successfully by running rustc --version again.

Help me troubleshoot my project folder setup.

Your environment is ready. Next up, you will learn how hashmaps work under the hood before building your word counter.

Understand How HashMaps Work

Your project directories are set up and ready to go. Before you write any code, you need to understand the data structure at the heart of this project: the HashMap.

Both Python and Rust use hashmaps to solve the word-counting problem. Understanding how they work under the hood will make the code you write in the next steps click instantly.

In this step, get ready to:
  • Understand what a hashmap is and how key-value pairs work.
  • Learn how hash functions convert keys into memory locations for fast lookups.
  • Identify the core operations you will use to build your word frequency counter.
Learn what a hashmap stores

A hashmap stores data as key-value pairs. Each key maps to exactly one value.

What is a key-value pair?

Think of a real-world dictionary. You look up a word (the key) and find its definition (the value). A hashmap works the same way. You store a key like "hello" and associate it with a value like 3 (meaning the word "hello" appeared 3 times).

The critical rule is that each key can only appear once. If you insert the same key again, the old value gets replaced. This makes hashmaps perfect for counting, because every word gets exactly one counter.

In Python, hashmaps are called dictionaries (the dict type). In Rust, they are called HashMap and live in the standard library at std::collections::HashMap.

Understand how hashing gives you speed

What makes a hashmap fast is the hash function working behind the scenes. When you store a key, the hash function converts it into a numeric index. That index determines exactly where in memory the value gets stored.

Why is this so fast?

Because the hash function always produces the same index for the same key, looking up a value is nearly instant. You don't need to search through every item one by one. You just compute the index and jump straight to the value.

This is called O(1) average-time lookup. It means finding a value by its key takes roughly the same amount of time whether your map holds 10 items or 10 million.

What about collisions?

Sometimes two different keys produce the same index. This is called a collision. Every hashmap implementation has a strategy for handling this (like chaining entries at the same index). You won't need to manage collisions yourself. Both Python and Rust handle them automatically.

Know the five core operations

Every hashmap supports the same set of core operations. These are the building blocks you will use to build your word frequency counter in the next steps.

  • Insert a key-value pair. Example: store the word "hello" with a count of 1.
  • Look up a value by key. Example: check how many times "hello" has appeared so far.
  • Update an existing value. Example: increment the count for "hello" from 1 to 2.
  • Delete a key-value pair. Example: remove "hello" from the map entirely.
  • Check if a key exists. Example: ask whether "hello" is already in the map before deciding to insert or update.

Which operations matter most for word counting?

For a word frequency counter, the most important pattern is the check-then-update combo: check if the word exists, and if so, increment its count. If not, insert it with a count of 1.

Python handles this with dict.get(key, 0). Rust handles it with the entry().or_insert() pattern. You will see both in action soon.

You now have the mental model you need. Next up, you will put this knowledge into practice by building your first word frequency counter in Python.

Build the Python Word Frequency Counter

You now understand how hashmaps store key-value pairs and deliver fast lookups through hashing. It's time to turn that knowledge into working code.

In this step, you'll write a Python script that takes a text sample, splits it into individual words, and uses a dictionary to count how often each word appears. By the end, you'll have a working frequency counter that displays results in a formatted table.

In this step, get ready to:
  • Create a word-counting function using Python's dictionary.
  • Add sorting logic to rank words by frequency.
  • Run the program and verify the output.
Create the word counting function

The core of any frequency counter is a function that reads through text and tallies each word. Python's dict.get() method makes this simple. It returns the current count for a word if it exists, or a default value of 0 if the word hasn't been seen yet.

  • Navigate to your word-freq-python directory by running this command:
cd ~/Desktop/word-freq-python
  • Create a new file called word_freq.py by running:
touch word_freq.py
  • Open word_freq.py in your code editor and add the following code:
import sys


def count_words(text):
    """Count word frequencies in the given text."""
    word_counts = {}
    for word in text.lower().split():
        word_counts[word] = word_counts.get(word, 0) + 1
    return word_counts

What does this code do?

  • import sys brings in the system module, which you'll use later when extending this program.
  • text.lower().split() converts the entire text to lowercase, then splits it into a list of individual words on whitespace.
  • word_counts.get(word, 0) + 1 looks up the current count for the word. If the word hasn't been counted yet, it returns 0 as a default, then adds 1.
  • Save word_freq.py.
  • You won't see a change yet. The next chunk adds sorting, and then the main() function will tie everything together.
Add sorting logic to display results by frequency

A raw dictionary has no guaranteed order. To show the most frequent words first, you need a function that sorts the dictionary entries by count (descending) and breaks ties alphabetically.

  • In word_freq.py, add the following function below count_words:
def sort_by_frequency(word_counts):
    """Sort word counts by frequency (highest first), then alphabetically."""
    sorted_words = sorted(word_counts.items(), key=lambda item: (-item[1], item[0]))
    return sorted_words

What does this code do?

  • word_counts.items() converts the dictionary into a list of (word, count) tuples so they can be sorted.
  • key=lambda item: (-item[1], item[0]) tells Python how to rank each tuple. The negative count (-item[1]) sorts high counts first. The word (item[0]) breaks ties alphabetically.
  • Save word_freq.py.
  • You won't see output yet. The next chunk adds the main() function that calls both functions and prints results.
Run the program and verify the output

The main() function ties everything together. It defines a hardcoded text sample, passes it through both functions, and prints a formatted frequency table.

  • Add the following code below sort_by_frequency in word_freq.py:
def main():
    text = (
        "rust is reliable rust is fast rust is productive "
        "python is easy python is versatile python is popular "
        "both are great both are useful"
    )

    print("=== Word Frequency Analyzer (Python) ===\n")
    print(f"Input text: {text}\n")

    word_counts = count_words(text)
    sorted_words = sort_by_frequency(word_counts)

    print(f"{'Word':<15} {'Count':>5}")
    print("-" * 22)
    for word, count in sorted_words:
        print(f"{word:<15} {count:>5}")

    print(f"\nTotal unique words: {len(word_counts)}")


if __name__ == "__main__":
    main()

What does this code do?

  • The text variable holds a multi-line sample string with repeated words like "rust", "is", and "python" for testing.
  • count_words(text) and sort_by_frequency(word_counts) call the two functions you just wrote in sequence.
  • The f-string format specifiers ({word:<15} and {count:>5}) create aligned columns. <15 means left-align in 15 characters. >5 means right-align in 5 characters.
  • if __name__ == "__main__" ensures main() only runs when you execute the file directly, not when it's imported as a module.
  • Save word_freq.py.
  • Run the program by running this command in your terminal:
python3 word_freq.py

You should see a formatted table showing each word and its count, with "is" at the top (appearing 6 times) and "Total unique words: 12" at the bottom.

Not seeing output or getting an error?

  • If you see IndentationError, check that all lines inside each function are indented with exactly 4 spaces. Mixing tabs and spaces causes this.
  • If nothing prints at all, make sure the if __name__ == "__main__": line and main() call are at the bottom of your file with no indentation.
  • If you see NameError: name 'count_words' is not defined, the count_words function must appear above main() in the file.

Why isn't my Python word frequency script producing output?

✔️ Awesome, I've got everything!

Great. Double check you've saved your file before moving on.

ⓧ I'd like to double check the full code

Here's the complete word_freq.py file. Make sure your code matches this exactly:

import sys


def count_words(text):
    """Count word frequencies in the given text."""
    word_counts = {}
    for word in text.lower().split():
        word_counts[word] = word_counts.get(word, 0) + 1
    return word_counts


def sort_by_frequency(word_counts):
    """Sort word counts by frequency (highest first), then alphabetically."""
    sorted_words = sorted(word_counts.items(), key=lambda item: (-item[1], item[0]))
    return sorted_words


def main():
    text = (
        "rust is reliable rust is fast rust is productive "
        "python is easy python is versatile python is popular "
        "both are great both are useful"
    )

    print("=== Word Frequency Analyzer (Python) ===\n")
    print(f"Input text: {text}\n")

    word_counts = count_words(text)
    sorted_words = sort_by_frequency(word_counts)

    print(f"{'Word':<15} {'Count':>5}")
    print("-" * 22)
    for word, count in sorted_words:
        print(f"{word:<15} {count:>5}")

    print(f"\nTotal unique words: {len(word_counts)}")


if __name__ == "__main__":
    main()

Your Python frequency counter is working. Next up, you'll rebuild the same program in Rust using HashMap and see how ownership and the entry API change the approach.

Build the Rust Word Frequency Counter

Your Python word counter works. Now it's time to solve the exact same problem in Rust, where the language forces you to think more carefully about who owns the data and how it's stored.

Rust's HashMap lives in the standard library and uses a special pattern called the entry API to handle inserting and updating values safely.

In this step, get ready to:
  • Write a word counting function using HashMap's entry API.
  • Add sorting logic to display results by frequency.
  • Run the program and verify it matches the Python output.
Write the word counting function using HashMap's entry API

Rust's HashMap is not included in the prelude, so you need to import it explicitly from std::collections. The entry API lets you look up a key and insert a default value if it doesn't exist, all in one step.

  • In Cursor, open src/main.rs inside your word-freq-rust folder.
  • Select all the auto-generated code and delete it.
  • Add the HashMap import and the count_words function by pasting this code:
use std::collections::HashMap;

// Count how many times each word appears in the input text
fn count_words(text: &str) -> HashMap<String, usize> {
    // Create an empty HashMap to store word counts
    let mut word_counts = HashMap::new();
    for word in text.split_whitespace() {
        // Normalize each word to lowercase for consistent counting
        let normalized = word.to_lowercase();
        // entry() looks up the key; or_insert(0) sets it to 0 if missing
        let count = word_counts.entry(normalized).or_insert(0);
        // Dereference the mutable reference to increment the value
        *count += 1;
    }
    word_counts
}

What does this code do?

The function takes a string slice (&str) as input and returns a HashMap<String, usize> where each key is a word and each value is how many times it appeared.

The line word_counts.entry(normalized).or_insert(0) is Rust's entry API. It checks if the key exists. If it does, it returns a mutable reference to the value. If it doesn't, it inserts 0 first, then returns the reference. The *count += 1 dereferences that reference to increment the actual value in the map.

Why entry() instead of get/insert?

In Python, you used dict.get(key, 0) + 1 to handle missing keys. Rust's entry API serves the same purpose but does it in a single step without needing to look up the key twice. This pattern is idiomatic Rust for conditional insert-or-update operations.

You won't see output yet. The next chunk adds sorting, and the main function will tie everything together.

Add sorting logic to convert the HashMap to a sorted list

HashMaps iterate in arbitrary order. To display results sorted by frequency, you need to convert the HashMap into a Vec of tuples and sort it.

  • Add the sort_by_frequency function below count_words by pasting this code:
fn sort_by_frequency(word_counts: HashMap<String, usize>) -> Vec<(String, usize)> {
    // Convert the HashMap into a Vec of (word, count) tuples
    let mut sorted_words: Vec<(String, usize)> = word_counts.into_iter().collect();
    // Sort by count descending, then alphabetically for ties
    sorted_words.sort_by(|a, b| b.1.cmp(&a.1).then_with(|| a.0.cmp(&b.0)));
    sorted_words
}

What does this code do?

This function takes ownership of the HashMap (notice there's no & in the parameter). It uses into_iter().collect() to consume the map and produce a vector of tuples.

The sort_by closure compares b.1.cmp(&a.1) (count descending) and uses then_with for alphabetical tiebreaking. This mirrors your Python lambda that sorted by (-item[1], item[0]).

You still won't see output. The next chunk adds the main function that calls both helpers and prints results.

Complete the main function and run the program

The main function ties everything together. It declares the same hardcoded text sample you used in Python, calls your two helper functions, and prints a formatted table.

  • Add the main function below sort_by_frequency by pasting this code:
fn main() {
    // Same text sample as the Python version
    let text = "rust is reliable rust is fast rust is productive \
                python is easy python is versatile python is popular \
                both are great both are useful";

    println!("=== Word Frequency Analyzer (Rust) ===\n");
    println!("Input text: {}\n", text);

    let word_counts = count_words(text);
    // Save the count before sort_by_frequency takes ownership
    let total_unique = word_counts.len();
    let sorted_words = sort_by_frequency(word_counts);

    // Print a formatted table header
    println!("{:<15} {:>5}", "Word", "Count");
    println!("{}", "-".repeat(22));
    for (word, count) in &sorted_words {
        println!("{:<15} {:>5}", word, count);
    }

    println!("\nTotal unique words: {}", total_unique);
}

What does this code do?

Notice total_unique is captured before calling sort_by_frequency. That's because sort_by_frequency takes ownership of the HashMap (moves it). After the move, word_counts no longer exists and you can't call .len() on it. This is Rust's ownership system in action.

The \ at the end of each line in the text string is a line continuation. It lets you split a long string across multiple lines in your source code without inserting newline characters.

  • Save main.rs.
  • Return to your terminal and make sure you are inside the word-freq-rust directory.
  • Compile and run the program by running this command:
cargo run
  • You should see a table of words sorted by frequency, with "is" at the top (count 6) and a total unique words count at the bottom.

What should I see?

The output should look nearly identical to your Python version. The word order within the same frequency group may differ slightly because Rust's HashMap iterates in arbitrary order before sorting. The final counts are the same.

Seeing a compilation error?

Make sure you deleted all the auto-generated code before pasting. Having two fn main() definitions in the same file causes a conflict.

Check that use std::collections::HashMap; is the very first line in the file. If the import is missing, Rust won't recognize the HashMap type.

Confirm you're running cargo run from inside the word-freq-rust directory (the one containing Cargo.toml).

Help me debug my Rust HashMap word counter

✔️ Awesome, I've got everything!

Great. Double check you've saved your file and the output looks correct.

ⓧ I'd like to double check the full code

Here's the complete src/main.rs file. Compare it against yours:

use std::collections::HashMap;

fn count_words(text: &str) -> HashMap<String, usize> {
    let mut word_counts = HashMap::new();
    for word in text.split_whitespace() {
        let normalized = word.to_lowercase();
        let count = word_counts.entry(normalized).or_insert(0);
        *count += 1;
    }
    word_counts
}

fn sort_by_frequency(word_counts: HashMap<String, usize>) -> Vec<(String, usize)> {
    let mut sorted_words: Vec<(String, usize)> = word_counts.into_iter().collect();
    sorted_words.sort_by(|a, b| b.1.cmp(&a.1).then_with(|| a.0.cmp(&b.0)));
    sorted_words
}

fn main() {
    let text = "rust is reliable rust is fast rust is productive \
                python is easy python is versatile python is popular \
                both are great both are useful";

    println!("=== Word Frequency Analyzer (Rust) ===\n");
    println!("Input text: {}\n", text);

    let word_counts = count_words(text);
    let total_unique = word_counts.len();
    let sorted_words = sort_by_frequency(word_counts);

    println!("{:<15} {:>5}", "Word", "Count");
    println!("{}", "-".repeat(22));
    for (word, count) in &sorted_words {
        println!("{:<15} {:>5}", word, count);
    }

    println!("\nTotal unique words: {}", total_unique);
}

Your Rust word counter is working. Next up, you'll compare both implementations side by side to see how the same hashmap problem plays out differently in each language.

Compare Both Implementations Side by Side

You've built the same word frequency tool in two different languages. Now it's time to run them together and see how Python and Rust solve the exact same problem with fundamentally different philosophies.

Both programs use the same input text, the same counting logic, and the same sorting approach. The differences lie in how each language handles memory, mutability, and hashmap operations.

In this step, get ready to:
  • Run both programs and compare their output.
  • Identify the key differences between Python's dictionary pattern and Rust's entry API.
  • Confirm both programs produce identical word counts.
Run both programs side by side

Both programs already use the same hardcoded multi-line text sample. Running them back-to-back lets you compare the output directly.

  • Run the Python version by navigating to your word-freq-python folder and running this command:
cd ~/Desktop/word-freq-python
python3 word_freq.py

You should see a table with words sorted by frequency, followed by a total unique words count.

  • Now run the Rust version by navigating to your word-freq-rust folder and running this command:
cd ~/Desktop/word-freq-rust
cargo run

You should see the same word frequency table with matching counts and the same total unique words number.

Output doesn't match between versions?

If the word counts differ, check that both programs use the exact same input text string. A missing space or extra word in one version will produce different counts.

If the sort order differs, that's expected for words with the same frequency. Both programs sort alphabetically as a tiebreaker, but double-check your sort logic matches the Complete Code.

Why are my Python and Rust word counts different?

Observe the key differences in approach

Both programs solve the same problem, but the code patterns reveal each language's philosophy. Open both files side by side in Cursor to compare them.

  • Open word_freq.py and main.rs side by side.
  • Look at the counting logic in each file's count_words function.

In Python, the counting pattern looks like this:

word_counts[word] = word_counts.get(word, 0) + 1

In Rust, the same operation requires the entry API and explicit dereferencing:

let count = word_counts.entry(normalized).or_insert(0);
*count += 1;

Why does Rust need two lines for what Python does in one?

Python's dict.get(key, 0) returns a value directly. You can add 1 and assign it back in one expression because Python handles memory automatically.

Rust's entry().or_insert(0) returns a mutable reference to the value inside the HashMap. The *count dereferences that reference to modify the actual value stored in the map. This explicitness is how Rust guarantees memory safety at compile time.

What other differences stand out?

  • Rust requires let mut to declare the HashMap as mutable. Python dicts are mutable by default.
  • Rust's to_lowercase() creates a new owned String because the HashMap takes ownership of its keys. Python's .lower() also creates a new string, but ownership is invisible.
  • Rust requires type annotations on the HashMap (HashMap<String, usize>). Python infers types dynamically at runtime.
  • Rust's sorting uses .sort_by() with a closure that explicitly compares tuple fields. Python uses sorted() with a lambda key function.
Confirm identical results

Both programs include a "Total unique words" summary line at the bottom of their output. This is your proof that despite the different syntax and memory models, both languages produce the exact same result.

  • Run the Python version one more time:
cd ~/Desktop/word-freq-python
python3 word_freq.py
  • Run the Rust version one more time:
cd ~/Desktop/word-freq-rust
cargo run
  • Compare the last line of each program's output. Both should display Total unique words: 12.
  • Verify that the word counts match. For example, "is" appears 6 times and "rust" appears 3 times in both outputs.

Why do both programs produce 12 unique words?

The input text contains exactly 12 distinct words after lowercasing: rust, is, reliable, fast, productive, python, easy, versatile, popular, both, are, great, useful. Both programs normalize to lowercase before counting, so capitalization differences never create duplicate keys.

✔️ Awesome, I've got everything!

Great. Both programs should produce identical word counts and the same total of 12 unique words.

ⓧ I'd like to double check the full code

Here is the complete Python file:

import sys


def count_words(text):
    """Count word frequencies in the given text."""
    word_counts = {}
    for word in text.lower().split():
        word_counts[word] = word_counts.get(word, 0) + 1
    return word_counts


def sort_by_frequency(word_counts):
    """Sort word counts by frequency (highest first), then alphabetically."""
    sorted_words = sorted(word_counts.items(), key=lambda item: (-item[1], item[0]))
    return sorted_words


def main():
    text = (
        "rust is reliable rust is fast rust is productive "
        "python is easy python is versatile python is popular "
        "both are great both are useful"
    )

    print("=== Word Frequency Analyzer (Python) ===\n")
    print(f"Input text: {text}\n")

    word_counts = count_words(text)
    sorted_words = sort_by_frequency(word_counts)

    print(f"{'Word':<15} {'Count':>5}")
    print("-" * 22)
    for word, count in sorted_words:
        print(f"{word:<15} {count:>5}")

    print(f"\nTotal unique words: {len(word_counts)}")


if __name__ == "__main__":
    main()

Here is the complete Rust file:

use std::collections::HashMap;

fn count_words(text: &str) -> HashMap<String, usize> {
    let mut word_counts = HashMap::new();
    for word in text.split_whitespace() {
        let normalized = word.to_lowercase();
        let count = word_counts.entry(normalized).or_insert(0);
        *count += 1;
    }
    word_counts
}

fn sort_by_frequency(word_counts: HashMap<String, usize>) -> Vec<(String, usize)> {
    let mut sorted_words: Vec<(String, usize)> = word_counts.into_iter().collect();
    sorted_words.sort_by(|a, b| b.1.cmp(&a.1).then_with(|| a.0.cmp(&b.0)));
    sorted_words
}

fn main() {
    let text = "rust is reliable rust is fast rust is productive \
                python is easy python is versatile python is popular \
                both are great both are useful";

    println!("=== Word Frequency Analyzer (Rust) ===\n");
    println!("Input text: {}\n", text);

    let word_counts = count_words(text);
    let total_unique = word_counts.len();
    let sorted_words = sort_by_frequency(word_counts);

    println!("{:<15} {:>5}", "Word", "Count");
    println!("{}", "-".repeat(22));
    for (word, count) in &sorted_words {
        println!("{:<15} {:>5}", word, count);
    }

    println!("\nTotal unique words: {}", total_unique);
}

Secret mission

Add File Reading and Bar Chart Visualization

Your word frequency analyzer works great with hardcoded text. But real tools read from files and present data visually. Can you extend both programs to accept a file path, display only the top 10 words, and render a horizontal bar chart in the terminal?

Clean Up Your Resources

Clean Up Your Resources

Decide whether to keep your resources running, pause them to come back later, or delete them entirely. This project runs entirely locally, so there are no ongoing costs.

Resources you used:

  • word-freq-python/ directory (Python project files).
  • word-freq-rust/ directory (Rust project files and compiled binaries).
  • Rust toolchain (installed via rustup).

Keep everything running

No action needed. Choose this if you plan to keep experimenting with Rust and Python on your machine.

  • Your project folders stay on your Desktop where you created them.
  • Rust remains installed and available via rustc and cargo.
  • Python remains installed and available via python3.

Pause - I'll come back to this later

There are no running processes or cloud resources to pause. Your files sit on disk and take up minimal space until you return.

  • Your project folders remain on your Desktop.
  • Rust and Python stay installed. No ongoing memory or CPU is used when you are not running the programs.

Delete - I don't want to use this again

Remove all project files and optionally uninstall Rust from your system.

  • Delete both project directories by running these commands:
cd ~/Desktop
rm -rf word-freq-python word-freq-rust

On Windows, use this command instead:

cd ~\Desktop
rmdir /s /q word-freq-python word-freq-rust
  • Uninstall Rust and all its toolchains by running:
rustup self uninstall

This removes all Rust toolchains, cargo, and rustup from your system. Type y when prompted to confirm.

That's a Wrap!

That's a Wrap!

Nice work! You just built a word frequency analyzer in two languages, proving you can apply hashmap operations in both Python and Rust.

You've learned how to:

  • Use hashmaps as a key-value data structure with O(1) average lookups powered by hash functions.
  • Build a Python dictionary-based word counter with frequency sorting using dict.get() and sorted().
  • Build a Rust HashMap-based word counter using the entry API pattern (entry().or_insert()) and Rust's ownership model.
  • Extended both programs to read files from the command line and display visual bar charts in the terminal.

Ready to quiz yourself?