Mappings and arrays

The two primary data structures in Solidity — and when to use each one.

Mappings

Mappings are the most important data structure in Solidity. They work like hash maps: given a key, they return a value. All keys default to their zero value — you don't need to initialize them.

solidity
mapping(address => uint256) public balances;
mapping(address => mapping(address => uint256)) public allowances;  // nested mapping

Mappings cannot be iterated over or returned from functions — they have no notion of "all keys." If you need to track which keys exist, maintain a separate array alongside the mapping.

solidity
mapping(address => uint256) public balances;
address[] public holders;

function _addHolder(address account) internal {
    if (balances[account] == 0) {
        holders.push(account);
    }
}

Arrays

Arrays come in fixed-size and dynamic variants.

solidity
uint256[5] public fixedArray;          // always 5 elements
uint256[] public dynamicArray;          // can grow or shrink
address[] public whitelist;

Common array operations

solidity
contract ArrayExample {
    uint256[] public values;

    function add(uint256 val) public {
        values.push(val);
    }

    function remove(uint256 index) public {
        // Swap with last element and pop — order-independent removal
        values[index] = values[values.length - 1];
        values.pop();
    }

    function length() public view returns (uint256) {
        return values.length;
    }

    function get(uint256 index) public view returns (uint256) {
        require(index < values.length, 'Out of bounds');
        return values[index];
    }
}

Memory arrays

Arrays created inside functions with memory are temporary — they don't cost storage gas but must have a fixed size declared at creation.

solidity
function getTopN(uint256 n) public view returns (uint256[] memory) {
    uint256[] memory result = new uint256[](n);
    for (uint256 i = 0; i < n; i++) {
        result[i] = values[i];
    }
    return result;
}

Mapping vs. array — when to use which

  • Use a mapping when you look up values by key (e.g., user balances, allowances, ownership)
  • Use an array when you need to iterate or return a list
  • Use both together when you need both lookup and iteration

In practice, most ERC-20 token contracts use mapping(address => uint256) for balances — fast O(1) lookup at the cost of no native iteration.

←   Control flowStructs and enums   →