0%
Overview page background
HomeOverviewsLearn Solidity
What is mapping in Solidity?

What is mapping in Solidity?

Alchemy headshot

Written by Alchemy

Brady Werkheiser headshot

Reviewed by Brady Werkheiser

Published on October 4, 20224 min read

Mappings in Solidity are hash tables that store data as key-value pairs, where the key can be any of the built-in data types supported by Ethereum. Mappings are a fundamental concept to understand when learning Solidity development.

This article explains what mappings are, how mappings work, the differences between mappings and arrays, and provides examples of mappings so you can develop the best smart contracts on Ethereum and Solidity-compatible blockchains like Optimism and Arbitrum.

A hash table is a data structure that stores data associatively. Data is kept in an array format in a hash table, with each data value having its own unique index value. Hash Tables use an array as a storage medium and employ the hash technique to establish an index from which an element is to be inserted or located.

Mappings in Solidity Explained by Doug Crescenzi
Source: Mappings in Solidity Explained by Doug Crescenzi

When the index of the needed data is known, it can get returned extremely quickly. As a result, hash tables are data structures in which insertion and search operations are extremely quick, regardless of the quantity of the data.

Mapping is a hash table in Solidity that stores data as key-value pairs, where the key can be any of the built-in data types, excluding reference types, and the value of the data type can be any type.

Mappings are most typically used in Solidity and the Ethereum blockchain to connect a unique Ethereum address to a corresponding value type.

In any other programming language, a mapping is equivalent to a dictionary.

Mappings function as hash tables, with key types and corresponding value type pairs, and mappings are valuable because they can hold a large number of _KeyTypes to _ValueTypes. Mappings do not have a length, nor do they have the concept of setting a key or a value. Mappings are only applicable to state variables that serve as store reference types. When mappings are initialized, they include every possible key, and are mapped to values whose byte-representations are all zeros.

Mappings are defined in Solidity in the same way as any other variable type:

Copied
mapping(address => uint) public userLevel;

Solidity arrays are better for iterating through a group of data (e.g. using a for loop), compared to mappings which are better when you will be able to obtain values based on a known key (i.e. you don't need to go over data).

Because iterating over an array in Solidity can be expensive compared to fetching data from mappings, and developers may want to store both a value and its key within a smart contract, developers sometimes create an array of keys that serve as a reference to data that can then be retrieved from inside a mapping.

Developers should never let an array in Solidity grow too large because iterating through a large array could cost more in Solidity gas fees than the transaction's value, making mappings a more gas efficient smart contract implementation.

Here are some additional qualities about mappings:

  • Mappings have no length.

  • Mappings also don't understand the concept of a key or a value being set.

  • Mappings can only be used for state variables that serve as storage reference types.

Nested mapping is mapping from one mapping to another. For example, if we have a username and age and want to store this information with the assistance of a special ID so that others can only get it with the aid of that ID, this is known as double mapping in Solidity.

Here is one nested mapping example:

Copied
pragma solidity >=0.7.0 <0.9.0; contract Nestmap { mapping(uint256=>mapping(string=>uint256)) public User;     function adduser(uint256 _Id,string memory _name, uint256 _age)public {     User[_Id][_name]=_age;     } }

In this contract, we built one nested mapping, which is referred to as a User. In that mapping, we linked two mappings:

  1. one for recording the information about the id of the specific user

  2. one for storing the name and age of the specific user.

The code block below is a simple getter function, which returns information of the user.

Copied
function user(uint256 _Id,string memory _name)public view returns(uint256) {   return User[_Id][_name];   }

Here is an example of using mappings in Solidity. The following code snippet functions are:

  • Mapping from address to uint and ensures the mapping always returns a value

  • If the value was never set, it will return the default value.

  • Updating the value at the mapped address

  • Resetting the value to the default value.

  • Creating a nested mapping from address to another mapping

  • Getting values from a nested mapping even when it is not initialized

Copied
pragma solidity ^0.8.13; contract Mapping { // Mapping from address to uint   mapping(address => uint) public myMap;      function get(address _addr) public view returns (uint) {   // Mapping always returns a value.     // If the value was never set, it will return the default value.     return myMap[_addr];    }         function set(address _addr, uint _i) public {    // Update the value at this address     myMap[_addr] = _i;    }        function remove(address _addr) public {    // Reset the value to the default value.     delete myMap[_addr];    }   }   contract NestedMapping { // Nested mapping (mapping from address to another mapping)   mapping(address => mapping(uint => bool)) public nested;      function get(address _addr1, uint _i) public view returns (bool) {   // You can get values from a nested mapping     // even when it is not initialized     return nested[_addr1][_i];    }        function set(    address _addr1,     uint _i,     bool _boo     ) public {     nested[_addr1][_i] = _boo;     }          function remove(address _addr1, uint _i) public {     delete nested[_addr1][_i];      }     }

Here are three examples of mappings in Solidity:

  1. ERC20 token balances

  2. Using boolean logic

  3. Looking up members of a DAO

This code snippet maps user addresses with their addresses' ERC20 balance.

Copied
contract ERC20 is Context, IERC20 {        using SafeMath for uint256;        using Address for address;         mapping (address => uint256) private _balances;    ...}

This code snippet is designed to list candidates names in a list and return how many votes the candidate received. This example has use cases with DAOs where members are expected to vote on organizational decisions.

Copied
contract Voting { mapping (bytes32 => uint8) public votesReceived;   mapping (bytes32 => bool) public candidateList;      function Voting(bytes32[] candidateNames) {   for(uint i = 0; i < candidateNames.length; i++) {         candidateList[candidateNames[i]] = true;  } } function totalVotesFor(bytes32 candidate) constant returns (uint8) { require(validCandidate(candidate));   return votesReceived[candidate];   }     function voteForCandidate(bytes32 candidate) {   require(validCandidate(candidate) == true);   votesReceived[candidate] += 1;   }   function validCandidate(bytes32 candidate) constant returns (bool) {   return candidateList[candidate];   } }

This example is from the Dominion DAO smart contract that maps raisedProposals, stakeholderVotes, votedOn, contributors, and stakeholders.

Copied
mapping(uint256 => ProposalStruct) private raisedProposals; mapping(address => uint256[]) private stakeholderVotes; mapping(uint256 => VotedStruct[]) private votedOn; mapping(address => uint256) private contributors; mapping(address => uint256) private stakeholders;

This code example lists fields for two Solidity structs: ProposalStruct and VotedStruct.

Copied
struct ProposalStruct {     uint256 id;   uint256 amount;   uint256 duration;   uint256 upvotes;   uint256 downvotes;   string title;   string description;   bool passed;   bool paid;   address payable beneficiary;   address proposer;   address executor;  }   struct VotedStruct {  address voter;  uint256 timestamp;  bool choosen; }

Let's try adding some values to the mapping while it's being built for better understanding. In the following example, we:

  • Create a contract

  • Define a structure

  • Declare different structure elements

  • Create a mapping

  • Add values to the mapping

Copied
// Solidity program to // demonstrate adding // values to mapping pragma solidity ^0.4.18; // Creating contract contract mapping_example { //Defining structure   struct student {      //Declaring different     // structure elements     string name;       string subject;       uint8 marks;     }          // Creating mapping     mapping (     address => student) result;     address[] public student_result;          // Function adding values to     // the mapping     function adding_values() public {     var student       = result[0xDEE7796E89C82C36BAdd1375076f39D69FafE252];              student.name = "John";       student.subject = "Chemistry";       student.marks = 88;       student_result.push(       0xDEE7796E89C82C36BAdd1375076f39D69FafE252) -1;     } }

Here are a few frequently asked questions about Solidity mappings:

  1. What is the Solidity mapping length?

  2. What are the default values of Solidity mappings?

  3. How can you publicly see Solidity mappings?

Mappings do not have a length. A key's data is not saved in a mapping, but rather its keccak256 hash is used to store the value to which the key data refers. There is no concept of a key and a value "by themselves."

Here are the default value types for Solidity mappings:

  • int/uint - key type = yes; value type = yes

  • string - key type = yes; value type = yes

  • byte/bytes - key type = yes; value type = yes

  • address - key type = yes; value type = yes

  • struct - key type = no; value type = yes

  • mapping - key type = no; value type = yes

  • enum - key type = no; value type = yes

  • contract - key type = no; value type = yes

  • fixed-sized array - key type = yes; value type = yes

  • dynamic-sized array - key type = no; value type = yes

  • multi-dimensional array - key type = no; value type = yes

  • variable - key type = no; value type = no

Because the property is public, you can use the getter function created by the Solidity compiler to access it.

Copied
const myContract = new web3.eth.Contract(abiJson, contractAddress); // returns value of the mapping for the key `0` const info = await myContract.methods.locks(0).call();
Overview cards background graphic
Section background image

Build blockchain magic

Alchemy combines the most powerful web3 developer products and tools with resources, community and legendary support.

Get your API key