0

I need a function that willl return an array of size n and have each element be a 1. How do I write this in solidity? I need something like uint256[] a = makeOnesArray(5) => [1, 1, 1, 1, 1]

1 Answer 1

0

There are fixed size and dynamic array types to choose from. The former are immediately laid out with the requested elements initialized to binary zero values and they have no length property. The elements can be written to within the range of 0 to length-1.

The latter are initialized with zero length and a have a length property. You can append with the .push() method and you must do that to extend the length. You cannot write past the end (length-1) so a write is not possible when the length is 0 - the initial state.

The idea of initializing all elements to 1 is inefficient. The problems will become more pronounced at scale (more rows). You can consider an offset or similar strategy to store zero as much as possible (it is a default, so there are efficiencies there), and a function to translate so you get the effect of initializing everything to 1. The more elements involved, the greater the efficiency improvement.

Using 5 elements (the divergence will increase with the number of elements):

  • Fixed size array, naively writing 1 to each element: 247K gas
  • Dynamic array, appending 1 five times: 273K gas
  • Fixed size using an offset to represent 1: 194K gas
  • Variable size using an offset to represent 1: 236K

In summary, use fixed when possible and devise a way to minimize writes if possible. Be aware there are different syntax and properties when switching between fixed size and dynamic arrays. If it helps remember what's going on, a fixed array has the length compiled in the bytecode, whereas a dynamic array has a uint256 value stored and it is updated every time an element is pushed or popped, i.e. array.push(1) is two writes (SSTORE) - one to increase the length and one to write the new element.

// SPDX-License-Identifier: UNLICENSED

pragma solidity 0.8.7;

// If the size is known and fixed, elements are writable and there is no length property

contract FixedSize {

    uint256[5] public elements;

    constructor() {         // 246846 gas to deploy
        elements[0] = 1;
        elements[1] = 1;
        elements[2] = 1;
        elements[3] = 1;
        elements[4] = 1;
    }

    function length() public pure returns(uint256) {
        return 5;
    }
}

// If the size is variable, use push() and the length property of the array

contract VariableSize {

    uint256[] public elements;

    constructor() {         // 273420 gas to deploy
        elements.push(1);
        elements.push(1);
        elements.push(1);
        elements.push(1);
        elements.push(1);
    }

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

// writing data is expensive. Consider ways to minimize initialization, such as an offset from the default zero value.
// this gives you the "effect" of initializing all five elements to 1 without the expense of 5x write to storage.

contract FixedOffsetValue {

    uint256 private constant offset = 1;
    uint256[5] private element;

    // no constructor because there is nothing to do: 193921 gas

    function elements(uint256 row) public view returns(uint256) {
        return element[row] + offset;
    }

    function length() public pure returns(uint256) {
        return 5;
    }

}

// Combine offset with variable length. Writing zero is cheaper than writing one because it only incriments the array length and doesn't
// need to write a value (it's already zero). 

contract VariableOffsetValue {

    uint256 private constant offset = 1;
    uint256[] private element;

    constructor() {         // 235899 gas to deploy
        element.push(0);
        element.push(0);
        element.push(0);
        element.push(0);
        element.push(0);
    }

    function elements(uint256 row) public view returns(uint256) {
        return element[row] + offset;
    }

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

}

Hope it helps.

3
  • Whats the best way to go about this for my example. I need an array of 1s to pass into a safeBatchTransfer function (takes uint256[] ids and uint256[] amounts (all 1s since each token is non fungible but still an 1155)). Right now i have a function that takes an int N and returns an array of size N with 1 for each element to use for the transfer function. It will look a lot more confusing for the user but would it be better to get the caller to supply the 1s array as a parameter for my function ? Instead of using a helper function to make it? Commented Mar 10, 2022 at 5:23
  • In this case, batchTransfer does indeed have a max N. It doesn't render the contract unusable since a large batch can be split into smaller batches. Take care not to introduce a problem in your implementation. Commented Mar 12, 2022 at 4:27
  • I would do it the idiomatic way but as mentioned, you might need to accommodate multiple batches if N is too large. Commented Mar 12, 2022 at 4:29

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.