5/5
## Mastering Vyper HashMaps for Efficient Data Retrieval In smart contract development, choosing the right data structure is crucial for efficiency and usability. While lists (arrays) are useful for ordered collections, they rely on numerical indices for data access. This can become cumbersome when you need to retrieve information based on a specific identifier, like a name, rather than its position in a sequence. Let's explore how Vyper's `HashMap` provides a more intuitive solution for such scenarios. ### The Challenge with Index-Based Lookups Imagine storing information about people, including their names and favorite numbers. A common initial approach might involve using lists: one for names and another for corresponding favorite numbers. ```vyper # Previous approach (simplified) list_of_people: public(DynArray[Person, 10]) # Assuming a Person struct exists list_of_numbers: public(DynArray[uint256, 10]) ``` If we add "Patrick" first and then "Mariah", accessing Mariah's favorite number requires knowing her index (which would be `1` in this case). You'd need code like `self.list_of_numbers[1]`. This presents a problem: 1. **Inconvenience:** Users or other contracts interacting with yours need to know or discover the correct numerical index for the specific entry they want. 2. **Fragility:** If the order of elements changes (e.g., an item is removed), the indices shift, potentially leading to incorrect data retrieval. 3. **Type Limitation:** Lists strictly require integer indices. Attempting to access data using a non-integer key, like `self.list_of_people["Mariah"]`, will result in a compilation error. How can we look up data using a more meaningful identifier, like the person's name, directly? ### Introducing Vyper HashMaps (Mappings) Vyper offers a powerful data structure called `HashMap`, often referred to as a mapping in other smart contract languages like Solidity, or dictionaries/hash tables in traditional programming. A `HashMap` stores data as key-value pairs, allowing you to associate one piece of data (the key) directly with another (the value). **Core Concept:** * A `HashMap` maps keys of a specific type to values of another specific type. * The syntax for declaring a `HashMap` is: `HashMap[KeyType, ValueType]`. * This structure enables direct lookups using the key, bypassing the need for numerical indices. A key characteristic of `HashMap`s in Vyper (and mappings in Solidity) is how they handle lookups for keys that haven't been explicitly assigned a value. Instead of causing an error, they return the **default value** for the specified `ValueType`. Common default values include: * `0` for numerical types (`uint256`, `int128`, etc.) * `False` for `bool` * The zero address (`0x00...00`) for `address` * An empty string or empty bytes for `String` or `Bytes`. ### Implementing HashMaps in Vyper Let's modify our contract to use a `HashMap` for storing favorite numbers, using names as keys. 1. **Declare the HashMap State Variable:** We introduce a new state variable to hold our mapping. We'll map names (represented as `String` limited to 100 bytes) to favorite numbers (`uint256`). Making it `public` automatically creates a getter function. ```vyper # State variable declaration name_to_favorite_number: public(HashMap[String[100], uint256]) ``` 2. **Update the HashMap:** We need to modify the function responsible for adding data (e.g., `add_person`) to populate this new `HashMap` alongside any existing lists. When a new person is added, we store their favorite number using their name as the key. ```vyper @external def add_person(name: String[100], favorite_number: uint256): # ... (previous logic, e.g., adding to lists) ... # Add the person to the hashmap # self refers to the contract's storage self.name_to_favorite_number[name] = favorite_number ``` Here, `self.name_to_favorite_number[name]` accesses the mapping slot corresponding to the provided `name`, and `= favorite_number` assigns the associated value. ### HashMap in Action: A Practical Example Let's trace the interaction with our updated contract: 1. **Deployment:** Immediately after deployment, the `name_to_favorite_number` mapping is empty in the sense that no keys have been explicitly set. If you were to query it using the automatically generated getter with the key "Mariah" (`name_to_favorite_number("Mariah")`), it would return `0`, the default value for `uint256`. 2. **Adding Data:** Now, we call the `add_person` function with the arguments `name = "Mariah"` and `favorite_number = 30`. This executes the code within the function, including the line `self.name_to_favorite_number["Mariah"] = 30`. 3. **Retrieving Data:** If you now query the mapping again using the key "Mariah" (`name_to_favorite_number("Mariah")`), it will return `30`. **The Benefit:** We can now directly retrieve Mariah's favorite number using her name as the identifier, without needing to know her position (index) in any list. This makes data retrieval far more intuitive and robust for use cases centered around specific identifiers rather than sequence order. ### Key Takeaways * `HashMap` in Vyper provides a key-value storage mechanism, mapping a unique key to a specific value. * It allows for direct data retrieval using the key, avoiding the limitations of index-based lookups found in lists. * Declare `HashMap`s using the syntax `HashMap[KeyType, ValueType]`. * Update values using the assignment syntax: `self.map_variable[key] = value`. * Unset keys in a `HashMap` return the default value for the `ValueType`. * `HashMap` and `List` are fundamental data structures in Vyper. Understanding when to use each is essential for building efficient and practical smart contracts. Choosing often involves considering factors like access patterns (direct lookup vs. iteration) and gas costs, which you'll become more familiar with through experience.
An essential introduction to Mastering Vyper HashMaps for Efficient Data Retrieval - Discover Vyper's `HashMap` structure for efficient key-value data storage and retrieval, contrasting it with index-based lists for direct lookups. Learn the syntax, implementation, and benefits of using meaningful keys over numerical indices.
Previous lesson
Previous
Next lesson
Next
Give us feedback
Course Overview
About the course
The basics of blockchain transactions, how to send and receive money on a blockchain network.
How to write Python based smart contracts using Vyper.
How to read and understand Vyper smart contracts.
Vyper data structures, arrays, structs, hash maps.
How to build a smart contract application and deploy on ZKsync with Moccasin.
Smart Contract Auditor
$100,000 - $200,000 (avg. salary)
On-chain Data Analyst
$59,000 - $139,000 (avg. salary)
DeFi Developer
$75,000 - $200,000 (avg. salary)
Smart Contract Engineer
$100,000 - $150,000 (avg. salary)
Web3 developer
$60,000 - $150,000 (avg. salary)
Web3 Developer Relations
$85,000 - $125,000 (avg. salary)
Last updated on June 11, 2025
Duration: 2h 08min
Duration: 2h 32min
Duration: 24min
Course Overview
About the course
The basics of blockchain transactions, how to send and receive money on a blockchain network.
How to write Python based smart contracts using Vyper.
How to read and understand Vyper smart contracts.
Vyper data structures, arrays, structs, hash maps.
How to build a smart contract application and deploy on ZKsync with Moccasin.
Smart Contract Auditor
$100,000 - $200,000 (avg. salary)
On-chain Data Analyst
$59,000 - $139,000 (avg. salary)
DeFi Developer
$75,000 - $200,000 (avg. salary)
Smart Contract Engineer
$100,000 - $150,000 (avg. salary)
Web3 developer
$60,000 - $150,000 (avg. salary)
Web3 Developer Relations
$85,000 - $125,000 (avg. salary)
Last updated on June 11, 2025