Wie lösche ich ein Element an einem bestimmten Index in einem Array?

Weiß jemand, wie man ein Element in einem Array löscht? Gibt es dafür eine eingebaute Methode?

Wenn nicht, weiß jemand, wie man eine solche Methode implementiert?

Möchten Sie das Element einfach löschen oder es löschen und alles einen Index nach unten verschieben?
Ich möchte, dass alles einen Index enthält. Wenn ich also a[2] lösche, wird a[3] zu a[2]

Antworten (7)

Verwenden Sie den deleteOperator, um das Element zu löschen:

delete array[index];

Wenn Sie keine Lücke hinterlassen möchten, müssen Sie jedes Element manuell verschieben:

contract test{
    uint[] array = [1,2,3,4,5];
    function remove(uint index)  returns(uint[]) {
        if (index >= array.length) return;

        for (uint i = index; i<array.length-1; i++){
            array[i] = array[i+1];
        }
        delete array[array.length-1];
        array.length--;
        return array;
    }
}

Wenn Ihnen die Reihenfolge egal ist, können Sie auch einfach das letzte Element in die leere Stelle kopieren und dann das letzte Element löschen.

Vielen Dank! Ich habe nur ein Problem mit der Funktion, die Sie gegeben haben, als Sie versuchten, sie "allgemeiner" zu machen: function remove(uint[] array,uint index) returns(uint[]) {gibt mir Error: Expression has to be an lvalue. array.length--;auch, kann diese Methode angepasst werden, um mit Arrays aller Typen (Strukturen usw.) zu arbeiten?
Ich bin mir nicht sicher, ob ich die Länge von Arrays im Speicher im Gegensatz zum Speicher verringern soll. Sie können alles in ein neues Array kopieren, denke ich, oder einfach diese Zeile entfernen und die nachgestellten Nullen belassen. Sie werden sowieso kein Gas sparen, indem Sie ein Speicherarray kürzer machen. Diese Methode sollte bei jedem Typ funktionieren, außer Mappings, da deletesie in Mappings nicht wirklich sinnvoll ist.
Wenn das Array sehr groß ist, zum Beispiel 1000 Objekte, sollte es nicht sehr viel Gas verbrauchen?
@TjadenHess ist es möglich, ein Array-Mitglied aus einem anderen Vertrag zu löschen, wenn das Array öffentlich ist? Ich weiß, dass es damit Probleme gibt, aber ich möchte das umsetzen. Danke im Voraus.
Nein, das kannst du nicht out of the box machen. Der andere Vertrag muss eine Funktion zum Löschen von Array-Elementen bereitstellen
Wie könnte ich das komplette Array löschen?
Diese Funktion kann den Vertrag blockiert lassen, wenn das Array sehr lang ist.
Durch Verringern der Array-Länge werden die Speicherplätze, die von den Out-of-Bounds-Elementen belegt sind, automatisch bereinigt. Die Leitung delete array[array.length-1];ist also überflüssig. Darüber hinaus werden der Transaktion 5000 Gas hinzugefügt, da die Gasrückerstattung nur dann gilt, wenn die Speicherung von einem Wert ungleich Null auf einen Wert von Null zurückgesetzt wird. Wenn es von Null auf Null gesetzt wird (vom Compiler hinzugefügt), kostet es 5000 Benzin.
Ich frage mich, ob es effizienter wäre, Assembly irgendwie zu verwenden, um Zeiger zu verschieben, um Lücken zu vermeiden, oder ein neues Array von der linken und rechten Seite der Lücke zu verketten
Nun, der richtige Weg, dies zu tun, wäre wahrscheinlich, eine verkettete Liste anstelle eines Arrays zu verwenden
Die beste Methode, die ich getestet habe, besteht darin, das letzte Element an die gelöschte Stelle zu kopieren, delete für den letzten Index aufzurufen und dann die Arraylänge zu verringern. Dies ist eine konstante Menge an Arbeit, nicht linear. Wenn Ihnen die Reihenfolge wichtig ist, sollten Sie eine zusätzliche Zuordnung von diesem Element zum nächsten haben, die Sie beim Hinzufügen und Löschen beibehalten.
Gibt es einen Vorteil, ein Element aus einem Array zu löschen, anstatt einen Nullwert zuzuweisen , wenn ich das Array nicht neu anordne ?
array.length--; löst einen Nur-Lese-Fehler in 0.7.0 aus
Ab 0.6.0 ist pop() die einzige Möglichkeit, die Größe des Arrays zu reduzieren. " Es ist nicht mehr möglich, die Größe von Speicher-Arrays zu ändern, indem man ihrer Länge einen neuen Wert zuweist " - docs.soliditylang.org/en/v0.8.11/…

Dieser Dauerbetrieb funktioniert ohne Wahrung der Ordnung:

uint[] internal array;

// Move the last element to the deleted spot.
// Remove the last element.
function _burn(uint index) internal {
  require(index < array.length);
  array[index] = array[array.length-1];
  array.pop();
}

Um die Reihenfolge beim Abrufen aufrechtzuerhalten, ohne die Gaskosten für das Verschieben von Werten für das Recht auf Lücke zu verursachen, benötigen Sie eine zusätzliche Zuordnung zwischen dem Index jedes Elements und dem Index seines Nachfolgers, die Sie während des Einfügens und Löschens beibehalten müssen:mapping(uint => uint) private indexAfter;

Beste Antwort!!!!
Definitiv der beste
Seit Solidity 0.6.0 sollte es nicht funktionieren ethereum.stackexchange.com/questions/80743/…
Schöne Lösung. Funktioniert auf 0.8.0

Kleine Optimierung zur Antwort von Tjaden Hess:

contract Test {
    uint[] array = [1,2,3,4,5];
    function remove(uint index)  returns(uint[]) {
        if (index >= array.length) return;

        for (uint i = index; i<array.length-1; i++){
            array[i] = array[i+1];
        }
        array.length--;
        return array;
    }
}

Ich habe die Linie delete array[array.length-1];vorher entfernt array.length--;. Das macht die Funktion um 5000 Gas billiger. Der Compiler bereinigt automatisch unbelegte Slots, wenn die Array-Länge verringert wird. Das Zurücksetzen des doppelten Speichers fügt 5000 Gas hinzu.

Ich habe diese Antwort nur für Speicher-Arrays gefunden, können Sie das bestätigen? Die array.length--; line löst eine Ausnahme aus. Wenn Sie es so ändern, dass kein Fehler mehr auftritt, wird das letzte Element des Arrays nicht entfernt.
@Nico, yup, array.length - funktioniert nur bei Speicher-Arrays, bei Speicher-Arrays ist die Länge nach der Zuweisung konstant. Wenn Sie ein Speicherarray unterschiedlicher Länge wünschen, müssen Sie ein neues Speicherarray deklarieren.
Was ist der Zweck der return-Anweisung am Ende der Funktion?
array.pop() anstelle von array.length - für solidity> 0,6 sogar für Speicher-Arrays.

Die meisten der vorherigen Antworten ändern direkt die Array-Länge, um ihre Länge zu reduzieren.

Seit Solidity 0.6.0 ist dies nicht mehr möglich

Der Mitgliedszugriff auf die Länge von Arrays ist jetzt immer schreibgeschützt, sogar für Speicher-Arrays. Es ist nicht mehr möglich, die Größe von Speicher-Arrays zu ändern, indem man ihrer Länge einen neuen Wert zuweist. Verwenden Sie stattdessen push(), push(value) oder pop() oder weisen Sie ein vollständiges Array zu, das natürlich vorhandene Inhalte überschreibt. Der Grund dafür ist, Speicherkollisionen durch gigantische Speicherarrays zu verhindern.

https://docs.soliditylang.org/en/v0.6.2/060-breaking-changes.html

Sie können die Antwort von medvedev1088 beheben mit:

contract Test {
    uint[] array = [1,2,3,4,5];
    function remove(uint index)  returns(uint[]) {
        if (index >= array.length) return;

        for (uint i = index; i<array.length-1; i++){
            array[i] = array[i+1];
        }
        array.pop();
        return array;
    }
}

Hinweis: array.pop();stattarray.length--;

pragma solidity ^0.4.11;
contract TestArray {
    uint[] public original;
    uint[] public newOr;
    event Log(uint n, uint a, uint b, uint c);

    function TestArray(){
        original.push(1);
        original.push(2);
        original.push(3);
        original.push(4);

    }

    function test(){
        newOr = remove(original, 1);
        Log(newOr.length, newOr[0], newOr[1], newOr[2]);
    }
    function remove(uint[] array, uint index) internal returns(uint[] value) {
        if (index >= array.length) return;

        uint[] memory arrayNew = new uint[](array.length-1);
        for (uint i = 0; i<arrayNew.length; i++){
            if(i != index && i<index){
                arrayNew[i] = array[i];
            } else {
                arrayNew[i] = array[i+1];
            }
        }
        delete array;
        return arrayNew;
    }

}
Wie kann ich das komplette Array löschen?
Sie müssen alle Elemente einzeln löschen. Das Array selbst kann nicht gelöscht werden, da es eine Speichervariable ist und für immer im Vertragsbereich bleibt.

a löschen weist a den Anfangswert für den Typ zu. Dh für ganze Zahlen ist es äquivalent zu a = 0, aber es kann auch auf Arrays verwendet werden, wo es ein dynamisches Array der Länge Null oder ein statisches Array derselben Länge mit zurückgesetzten Elementen zuweist. Für Strukturen weist es eine Struktur zu, bei der alle Mitglieder zurückgesetzt werden.

> Ich habe es implementiert, vielleicht hilft es, dieses einfache Beispiel zu verstehen

**

Und wenn wir das Element mit dem Index entfernen, bleibt die Lücke nicht.

**

http://solidity.readthedocs.io/en/v0.4.21/types.html

contract UserRecord {
    constructor() public { owner = msg.sender; }

    address owner;

    modifier onlyOwner {
        require(msg.sender == owner);
        _;
    }

    struct User {
        bytes32 userEmail;
        uint index;
    }

    mapping (bytes32 => User) private users;

    bytes32[] private usersRecords;
    event LogNewUser(bytes32 indexed userEmail, uint index);

    function setUseremail(bytes32 _userEmail) public onlyOwner returns(bool success){
        users[_userEmail].userEmail = _userEmail;
        users[_userEmail].index = usersRecords.push(_userEmail) -1;

        emit LogNewUser(
        _userEmail,
        users[_userEmail].index
        );
        return true;
    }

//this will delete the user at particular index and gap will be not there

    function deleteUser(bytes32 _userEmail) public onlyOwner returns(uint index){
        require(!isUser(_userEmail)); 
        uint toDelete = users[_userEmail].index;
        bytes32 lastIndex = usersRecords[usersRecords.length-1];
        usersRecords[toDelete] = lastIndex;
        users[lastIndex].index = toDelete; 
        usersRecords.length--;
        return toDelete;   
    }    
}

Eine Lösung, die im Vergleich zu anderen etwas mehr Gas verbraucht.

// Preload any custom data through other functions
address[] customArray;

function removeIndex(uint256 index) external {
    address[] storage _array = customArray;
    _array.push(_array[index]);
    for (uint i=index; i<_array.length-1; i++){
        _array[i] = _array[i+1];
    }
    _array.pop();
    _array.pop();
    customArray = _array;
}
Warum der Extraschub? Es scheint nutzlos.