[Ethereum] Changing dynamic array index content

arraysmappingsolidity

I'm trying to to make a contract which lets the user choose any number he likes to populate an array of integers used in a mapping.
Then he can choose any index of this array to increase its value by 1.

Below is the function that makes the increment:

    pragma solidity ^0.4.19;

    contract test {

       //the array size is chosen by the user
       mapping (bytes4 => int[]) internal map;

       function _increase(bytes4 _id,uint _index) public {        
           map[_id][_index] = map[_id][_index] + 1;
       }

    }

The problem is, unless you give the array in the mapping a fixed number like:

    mapping (bytes4 => int[1000]) internal map;

The function that increases its numbers throw an error (in remix):
Remix Error

Since giving this array any large random number to cover all the possibilities is a waste of unused space, can anyone think in a workarround?

Thanks a lot.

Best Answer

You're right. All the attempts to sparsely populate a dynamic array will fail because the index is out of bounds. You can make them longer with .push(value) but you want to be able to bounce around randomly.

On the other hand, you can actually lay out a map of very large fixed-size arrays without increasing gas cost as you might expect. This works:

pragma solidity ^0.4.19;

contract test {

  mapping (bytes4 => int[100000000000]) internal map;

  function _increase(bytes4 _id,uint _index) public {        
    map[_id][_index] = map[_id][_index] + 1;
  }

}

That still has an upper bound and it is not possible for the user to decide the dimensions. You can do this instead of thinking of the second index as an array:

contract Test {

   mapping (bytes32 => mapping(uint => uint)) public map;

   function increase(bytes32 id,uint index) public {        
       map[id][index] = map[id][index] + 1;
   }

}

The switch to bytes32 is because mapping indexes are always 32 bytes, and function inputs have to pack into 32-byte words. There is no savings by clipping it to 4 bytes.

You can make the mapping public to ease the process of retrieving values while testing gas cost with different setups.

Hope it helps.

Related Topic