Cómo llenar una matriz dinámica en memoria

Por alguna razón, la solidez no permite insertar valores en la matriz de memoria

El miembro "push" no está disponible en la memoria bytes32[] fuera del almacenamiento.

Aquí hay un código de contrato de muestra:

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;
    }
}

Podría asignar la máxima matriz de tamaño posible ny luego reducirla, pero puede afectar el rendimiento ( npodría ser del orden de magnitud de 100000mientras que la longitud final del resultado es 0..100). Por ejemplo, someConditionpodría ser isPrime. En este caso, tenemos un N grande (lo que hace imposible preasignar una matriz) y una pequeña lista de números primos resultantes.

¿Cómo se podría hacer?


Terminé preaplicando una matriz de tamaño ny luego reduciéndola una vez que sé que es la longitud final:

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 no está disponible para la matriz memroy, lea la documentación solidity.readthedocs.io/en/v0.4.21/types.html . para su nueva edición, debe omitir la palabra clave pura y agregar elementos usando un índice de matriz o usando una matriz de almacenamiento
@BadrBellaj No puedo usar un almacenamiento porque esta función no debería afectar el contrato.
si conoce el tamaño de la matriz, cree una matriz de memoria con longitud n: uint[] memory result = new uint[](n);
@BadrBellaj no, no lo hago. Traté de mejorar mi pregunta para que quede más clara, gracias.

Respuestas (4)

Las matrices dinámicas solo están disponibles en el almacenamiento, no en la memoria. En su caso, el tamaño de la resultmatriz se conoce por adelantado ( n). Entonces, puede simplemente declarar una matriz con una longitud de n. Luego puedes llenarlo usando i, que va de 0an - 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;
    }
}
Lo siento, fue un mal ejemplo. Por favor, vea editar.
sigo trabajando para 0.8.11 lol

que yo sé

push es solo para matrices de almacenamiento, no para matrices de memoria

del documento:

push: las matrices de almacenamiento dinámico y los bytes (no cadenas) tienen una función miembro llamada push que se puede usar para agregar un elemento al final de la matriz. La función devuelve la nueva longitud.

intentar

result[j]=keccak256(id);//declare j
¿No está fuera de los límites de acceso? ¿O debería implementar mi propio cambio de tamaño de matriz dinámica?
no para cambiar el tamaño de la matriz aquí está el documento solidity.readthedocs.io/en/develop/…
Bueno. Entonces, ¿tengo una lista de implementación manual? Asignar alguna matriz. Llenarlo. Cuando tengo que enviar otro elemento, debo asignar una nueva matriz, copiar todos los elementos de la anterior, reemplazar la matriz anterior por una nueva y finalmente agregar un elemento allí. Y cuando termine, ¿debería asignar otro conjunto a un resultado final y copiar todos los elementos en él? Supuse que hay alguna biblioteca (si el idioma no es compatible si está listo para usar). Consulte la pregunta actualizada si no estaba claro en el comentario.

Como tiene una condición en la iteración, agregaré esta clave en la respuesta de Henk:

pragma solidity ^0.4.21;

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

Usar almacenamiento en lugar de memoria

pragma solidity ^0.4.21;

contract Foo {
    function getRange(uint n) public view returns(uint[]) {
        uint[] storage result;
        for (uint i = 0; i < n; i++)
            if (i> 1)
               result.push(i);
        return result;
    }
}
El código tiene un error si no hay un vacío uint[]en la primera ranura.