25

I want to make a simple smart contract that has a list, can set item, and can get the list.

Code in solidity:

contract lister {
    mapping(int => string) list;
    int id = 0;
    
    function getList() returns ( /*HERE*/ ) {
        return list;
    }

    function setItemToList(string str) {
        list[id] = str;
        id++;
    }
}

I want to make getList() return the list, but the return type is not compatible. How can I do that?

Yilmaz
  • 35,338
  • 10
  • 157
  • 202
6londe
  • 557
  • 1
  • 8
  • 17

4 Answers4

23

Bulk access to lists/arrays/etc is painful in Solidity. You rarely see it in contracts. In your case, a possible solution is to provide a function to access one item, using its index, and to let the caller loop from 0 to id.

Pang
  • 9,564
  • 146
  • 81
  • 122
bortzmeyer
  • 34,164
  • 12
  • 67
  • 91
  • I believe the answer to this question is yes. In fact you can see which sites do this since they will be accessible without metamask installed. – jlansey Mar 26 '18 at 15:23
  • 1
    I am still looking for an answer to this, and so far, it seems the only way to get access to the entire list without executing a for loop/rate limited, is to process transaction/event history and store the data myself... which means I need to keep the data in sync at all times between my own storage and the blockchain... – xiao Sep 16 '21 at 04:57
8

With mappings, keys are not stored and the values can not be iterated upon, so they are really only good for single-value lookups. In the example you provide, it may be a better choice to use an array.

On the other hand, if you use an array and need to do a search on it (loop through all items), you need to be careful because if there are too many items in your array, it could end up costing a considerable amount of gas to call the function.

Alex
  • 335
  • 1
  • 4
  • 15
3

You can change the visibility of your variable list, insert public and it will possible to access this by getList.

mapping(int => string) public list;

HLeite
  • 47
  • 6
  • 2
    you should not do this. This makes map available to any one. So they can access the map without knowing key values. – e.k May 21 '18 at 14:54
  • 1
    @e.k It looks like OP wants to make the map available to anyone. Is there any other reason this is bad practice, or just bad if you want to keep it private? – dlsso Oct 28 '21 at 01:15
  • does this make anyone able to edit it ? – Eslam Mahmoud Nov 25 '21 at 15:57
0

Mappings do not store their keys, only the value which is stored at the state memory address. To get the list of data use an array.

address[] public addresses;

now define a function to get the length of this array:

   function getAddressCount() public view returns(uint){
        return addresses.length;
    }

Also define a function to get the element by index:

function getAddressByIndex(uint index) public view returns(address){

   return addresses[index]
}

now u need to write code to pull the get the array one by oen. This is how it is done in javascript with web3 library:

let addresses,addressCount;
try {
     addressesCount = await ContractName.methods.getCampaignCounts().call();
       
    addresses = await Promise.all(
      Array(parseInt(addressesCount))
        .fill()
        .map((element, index) => {
          return ContractName.methods.getAddressByIndex(index).call();
        })
    );
    
  } catch (e) {
    console.log("error in pulling array list", e);
  }
Yilmaz
  • 35,338
  • 10
  • 157
  • 202