7

For some reason solidity doesn't allow to push values into memory array

Member "push" is not available in bytes32[] memory outside of storage.

Here is sample contract code:

pragma solidity ^0.4.21;

contract Foo {
    function getRange(uint n) public pure returns(uint[]) {
        uint[] memory result;
        for (uint i = 0; i < n; i++)
            if (someCondition(i))
               result.push(i);
        return result;
    }
}

I could allocate maximum possible array of size n and then shrink it, but it may hurt performance (n could be in order of magnitude of 100000 while final length of result is 0..100). For example, someCondition could be isPrime. In this case we have large N (which makes impossible to preallocate an array) and small list of resulting prime numbers.

How could it be done?


I ended up with preallicating array of size n and then shrinking it once I know it's final length:

function getRange(uint n) public pure returns(uint[]) {
    uint tookCount = 0;
    uint[] memory result = new uint[](n);
    for (uint i = 0; i < n; i++)
        if (someCondition(i)) {
            result.push(i);
            tookCount++;
        }

    uint[] memory trimmedResult = new uint[](tookCount);
    for (uint j = 0; j < trimmedResult.length; j++) {
        trimmedResult[j] = result[j];
    }
    return trimmedResult;
}
  • push isn't available for memroy array read the documentation solidity.readthedocs.io/en/v0.4.21/types.html. for your new edit you have to omit the pure keyword and either you add elements using an array indice or by using a storage array – Badr Bellaj Apr 26 '18 at 11:53
  • @BadrBellaj I cannot use a storage because this function should not affect contract. – Alex Zhukovskiy Apr 26 '18 at 12:15
  • if you know the array size create a memory array with length n : uint[] memory result = new uint[](n); – Badr Bellaj Apr 26 '18 at 12:43
  • @BadrBellaj no, I don't. I tried to enhance my question to make it clearer, thank you. – Alex Zhukovskiy Apr 26 '18 at 13:13
9

Dynamic arrays are only available in storage, not in memory. In your case, the size of the result array is known upfront (n). So, you can just declare an array with length of n. Then you can fill it up using i, which goes from 0 to n - 1

pragma solidity ^0.4.21;

contract Foo {
    function getRange(uint n) public pure returns(uint[]) {
        uint[] memory result = new uint[](n);
        for (uint i = 0; i < n; i++)
            result[i] = i;
        return result;
    }
}
  • Sorry, it was a bad example. Please, see edit. – Alex Zhukovskiy Apr 26 '18 at 13:11
0

as i know

push is only for storage arrays not memory arrays

from the doc :

push: Dynamic storage arrays and bytes (not string) have a member function called push that can be used to append an element at the end of the array. The function returns the new length.

try

result[j]=keccak256(id);//declare j
  • Isn't it out of bounds access? Or I should implement my own dynamic array resize? – Alex Zhukovskiy Apr 26 '18 at 11:33
  • no for array resizing here's the doc solidity.readthedocs.io/en/develop/… – Badr Bellaj Apr 26 '18 at 11:56
  • Okay. So I have manually implement list? Allocate some array. Fill it. When I have to push yet another item I should allocate new array, copy all items from the old one, replace old array with new one and finally add an item there? And when I'm done I should allocate yet another array a final result, and copy all items in it? I supposed there is some library (if language isn't support if out of the box). Please see updated question if I was unclear in comment. – Alex Zhukovskiy Apr 26 '18 at 12:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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