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 mappingMappings 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.