0

I have this array of struct

struct Prodotto {
    string titolo;
    address owner_address;
}

Prodotto[] public prodotti;

And I create two products like this:

titolo: titolo stravolto
owner: 0x144c9617C69B52547f7c2c526352E137488FAF0c

titolo: titolo secondo prodotto
owner: 0xa53709839ab6Da3ad9c1518Ed39a4a0fFCbA3684

I want to delete the element with index 0

in my contract I have this function

function deleteProdotto(uint _id_prodotto) external payable onlyOwnerOf(_id_prodotto) {
  delete prodotti[0];    
}

If I retrive element to index 0, I have a product like this

titolo:
owner: 0x0000000000000000000000000000000000000000

How can I delete that index? I know that after that I have to do

prodotti.length--

But before I have to resolve this issue

2 Answers 2

2

It depends on why you feel the delete is necessary and what it means in the context of your application.

It can be handy, for example, to verify if there is, or isn't a Prodotto with a certain ID. For this, an array isn't ideal because it would need to be searched. A mapping can find it in one operation. You can also remove them and generally have fewer complications.

Consider

mapping(bytes32 => Prodotto) public prodottoStructs; where the key is a bytes32 unique ID.

Since mappings have one vexing limitation, namely that the keys can't be enumerated, an ID list can be a handy compliment.

bytes32[] public prodottoIdList;

You push Id values on to the list as you go. This doesn't give you a delete function, but you can do this with a boolean in the struct:

struct Prodotto {
    string titolo;
    address owner_address;
    bool isProdotto;   
}

You set the bool to true as you go. When you delete, it reverts to its default false value, which makes it easy to:

function isProdotto(bytes32 prodottoId) public view returns(bool isIndeed) {
  return prodottoStructs[prodottoId].isProdotto;
}

That's not too bad.

A mapping plus a list of ID values gives you a way to quickly check for existence, count the number that exist (including deleted ones) and enumerate the data that was created. If the existence of the keys for the previously created and subsequently deleted prodottos is problematic, then you can prune the list by moving the last key into the row to delete and shortening the list. Implicitly, that process means treating it as an unordered list of keys.

More on this: Are there well-solved and simple storage patterns for Solidity?

And the list reorganization option: https://medium.com/@robhitchens/solidity-crud-part-2-ed8d8b4f74ec

Hope it helps.

1
  • thanks a lot for your answer! I'm using the same approach of cryptoZombies about array and struct. I Want to be able to delete ("or flag it, it's good idea") a Product. for istance, I have a e-commerce, and each user can sell products. User can do CRUD about it. If I use flag, my list becomes huge, for this reason I think to delete it.
    – monkeyUser
    Commented Nov 9, 2018 at 10:35
2

There are a few issues with this approach. If you delete the element at index 0 and subtract 1 from the length, then the next time you try to insert an element, it'll overwrite the last element in the array. That's because delete prodotti[0] doesn't move the rest of the array to the left, it leaves the element in index 1 at index 1.

The reason you still get a struct from index 0 after deleting is because that's just how Solidity works. When you delete something from an array or mapping in Solidity, all you're really doing is zeroing out its values. That's why the struct it returns is all zeros.

IMO the best way to do this is leave it as you're doing it. Delete the element, but leave the length alone. Length is a misnomer really, it should be called tail or last because it's mostly used for knowing where the next element in the array will be.

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.