So füllen Sie ein dynamisches In-Memory-Array

Aus irgendeinem Grund erlaubt die Solidität nicht, Werte in das Speicherarray zu schieben

Member "push" ist im bytes32[]-Speicher außerhalb des Speichers nicht verfügbar.

Hier ist ein Beispielvertragscode:

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

Ich könnte das maximal mögliche Array der Größe zuweisen nund es dann verkleinern, aber es kann die Leistung beeinträchtigen ( nkönnte in der Größenordnung liegen, 100000während die endgültige Länge des Ergebnisses ist 0..100). Könnte zum Beispiel someConditionsein isPrime. In diesem Fall haben wir ein großes N (was die Vorabzuweisung eines Arrays unmöglich macht) und eine kleine Liste von resultierenden Primzahlen.

Wie könnte es gemacht werden?


Am Ende habe ich ein Größen-Array vorab zugewiesen nund es dann verkleinert, sobald ich weiß, dass es die endgültige Länge hat:

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 ist für das Memroy-Array nicht verfügbar. Lesen Sie die Dokumentation solidity.readthedocs.io/en/v0.4.21/types.html . Für Ihre neue Bearbeitung müssen Sie das Schlüsselwort pure weglassen und entweder Elemente mit einem Array-Index oder mit einem Speicher-Array hinzufügen
@BadrBellaj Ich kann keinen Speicher verwenden, da diese Funktion keinen Einfluss auf den Vertrag haben sollte.
Wenn Sie die Arraygröße kennen, erstellen Sie ein Speicherarray mit der Länge n: uint[] memory result = new uint[](n);
@BadrBellaj nein, tue ich nicht. Ich habe versucht, meine Frage zu verbessern, um sie klarer zu machen, danke.

Antworten (4)

Dynamische Arrays sind nur im Speicher verfügbar, nicht im Arbeitsspeicher. In Ihrem Fall ist die Größe des resultArrays im Voraus bekannt ( n). Sie können also einfach ein Array mit einer Länge von deklarieren n. Dann können Sie es mit auffüllen i, was von 0bis gehtn - 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;
    }
}
Entschuldigung, das war ein schlechtes Beispiel. Bitte siehe Bearbeiten.
funktioniert immer noch für 0.8.11 lol

wie ich weiss

push ist nur für Speicher-Arrays, nicht für Speicher-Arrays

aus dem Dokument:

push: Dynamische Speicher-Arrays und Bytes (nicht String) haben eine Member-Funktion namens push, die verwendet werden kann, um ein Element am Ende des Arrays anzuhängen. Die Funktion gibt die neue Länge zurück.

Versuchen

result[j]=keccak256(id);//declare j
Ist das nicht ein Zugang außerhalb der Grenzen? Oder sollte ich meine eigene dynamische Größenänderung des Arrays implementieren?
nein zur Größenänderung von Arrays hier ist das Dokument solidity.readthedocs.io/en/develop/…
Okay. Also muss ich die Liste manuell implementieren? Ordnen Sie ein Array zu. Es ausfüllen. Wenn ich noch ein weiteres Element verschieben muss, sollte ich ein neues Array zuweisen, alle Elemente aus dem alten kopieren, das alte Array durch ein neues ersetzen und dort schließlich ein Element hinzufügen? Und wenn ich fertig bin, soll ich noch einem weiteren Array ein Endergebnis zuweisen und alle Elemente darin kopieren? Ich nahm an, dass es eine Bibliothek gibt (wenn die Sprache nicht unterstützt wird, wenn sie sofort einsatzbereit ist). Bitte sehen Sie sich die aktualisierte Frage an, wenn ich im Kommentar unklar war.

Da Sie eine Bedingung in der Iteration haben, werde ich diesen Schlüssel in Henks Antwort hinzufügen:

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

Verwenden Sie Speicherplatz statt Arbeitsspeicher

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;
    }
}
Der Code hat einen Fehler, wenn uint[]der erste Slot nicht leer ist.