RoadToChain Logo
RoadToChain
T1/M1.1/Arrays and Mappings
beginner 12m read

Arrays and Mappings

Understanding O(1) lookup mappings versus dynamic iteration arrays.

#arrays #mappings #iteration

Let's trace a classic Web2 database problem:

Imagine you are building a registry of authorized accounts. In PostgreSQL, you would create a users table and check if a user is authorized by running SELECT EXISTS(SELECT 1 FROM users WHERE wallet_address = '0x71C...'). Behind the scenes, the database queries an index, or shuffles through rows.

When developers learn Solidity, they try to do this by creating a dynamic array address[] public authorizedUsers; and checking access by writing a for loop that iterates over the entire array list:

SmartAccount.sol
solidity
// ❌ HIGH-RISK ANTI-PATTERN: Loops scale gas linearly!
for (uint i = 0; i < authorizedUsers.length; i++) {
    if (authorizedUsers[i] == msg.sender) return true;
}

I genuinely thought this was the only way to manage lists. But as the array scales, this simple access check will consume more gas than the block limit allows, permanently freezing your contract!

To build secure, scalable smart contracts, you must master the differences between Arrays and Mappings.


1. The Metaphor: The Clipboard Checklist and the Locker Wall

Think of these two structures as completely different physical storage systems:

  • Arrays (The Clipboard Checklist): Imagine a long sheet of paper on a clipboard hanging on the wall. Every time you add a user, you write their name at the bottom of the list. If you want to check if a specific person is on the list, you must take the clipboard, start at line 1, and read line-by-line until you find the name or hit the bottom. If the checklist has 10,000 names, your eyes will fall out before you reach the end.
  • Mappings (The Locker Wall): Imagine a giant wall of security lockers. Every locker has a label that matches the hash of a wallet address. If you want to check if someone is authorized, you don't look through lists. You go directly to the locker door marked with their address. You put your hand on it—if the locker is unlocked (returns true), they are authorized. It takes exactly one second, whether there are 5 lockers or 5 million lockers on the wall.
Arrays vs Mappings — O(N) vs O(1) Lookup
Arrays preserve index order but require expensive linear searches, while mappings use direct slot hashing to deliver instant constant-time lookups.

// Reality Check

Mappings in Solidity have exactly O(1) constant-time lookup complexity. The EVM hashes the key (msg.sender) using Keccak256 math to find the exact, unique storage slot coordinate where the value lives. The size of your mapping has zero impact on transaction gas costs!

— Production Engineering Principle

2. Technical Breakdown: Mappings vs Arrays

Let's compare the two code styles directly:

SmartAccount.sol
solidity
// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;
 
contract AccessControlRegistry {
    // 1. ARRAY: Ordered list. Great for counting and index list retrieval.
    address[] public userList;
 
    // 2. MAPPING: Unordered hash map. Great for instant access checking.
    mapping(address => bool) public isAuthorized;
 
    function registerUser() public {
        require(!isAuthorized[msg.sender], "Already registered"); // O(1) Check!
        
        isAuthorized[msg.sender] = true; // Sets slot to true instantly
        userList.push(msg.sender); // Appends to list for historical tracking
    }
    
    function getUserCount() public view returns (uint256) {
        return userList.length; // Arrays know their size!
    }
}
  • Arrays: Can be resized, support dynamic iteration, and preserve order. However, searching them takes O(N) linear time and is extremely expensive in gas if iterated on-chain.
  • Mappings: Act like global hash maps. They take any key type and link it to a value. However, mappings have no concept of size, length, or iteration. You cannot loop over a mapping, and you cannot ask a mapping to list all its keys.

// I Got This Wrong

The Loop Disaster Trap: Never write a write transaction that loops over an array whose size can be inflated by users. This is a critical security vulnerability. If an attacker fills your array with 1,000 dummy entries, your loop will run out of gas, permanently blocking legitimate users from executing the function. This is the exact mistake analyzed in How I Broke My First Voting System.

— Postmortem Confession

3. Summary of Core Differences

| Feature | Dynamic Array (type[]) | Mapping (mapping(key => val)) | | :--- | :--- | :--- | | Lookup Cost | O(N) (Linear search required) | O(1) (Instant) | | Can Loop/Iterate? | Yes | No | | Has length field? | Yes | No | | Key/Index Type | strictly sequential uint256 | almost any type (address, bytes32, etc.) |


System Design Challenge
Think Active

Think about how you would design a system that needs both instant access authorization checks and the ability to list all registered users. Hint: look at the hybrid setup inside the AccessControlRegistry code above. How do they complement each other?

[ Think Before Continuing ]

Was this lesson helpful?

Let us know what you think of this specification. (submitting anonymously)