Skip to main content
added 6 characters in body
Source Link
haggis
  • 245
  • 1
  • 2
  • 10

Even though that's far from ideal (because it causes additional gas cost), this is how I do it now:

pragma solidity ^0.4.24;

contract MyContract {

  struct Person {
    uint age;
    uint size;
  }

  // Index of a person is its ID.
  Person[] persons;


  // The following holds a list of currently existing persons (without holes between the indexes)
  uint256[] personIds;

  // Holds the mapping from personID to its index in the above personIds array.
  mapping (uint256 => uint256) personIdToIndex;

  modifier personExists(uint256 _id) {
    uint256 index = personIdToIndex[_id]; // is 0 if not explicitly set
    require(personIds[index] == _id, "Person does not exist.");

    _;
  }

  event PersonAdded(uint indexed id, uint age, uint size);

  function addPerson(uint _age, uint _size) public {
    Person memory person = Person(_age, _size);
    id = persons.push(person) - 1;

    uint256 key = personIds.push(id) - 1;
    personIdToIndex[id] = key;

    emit PersonAdded(id, _age, _size)
  }

  function removePerson(uint _id) personExists(_id) public {
    delete persons[_id]

    // Reorganize index array and map
    uint256 key = personIdToIndex[_id]; 

    // Fill gap with last element of personIds
    personIds[key] = personIds[personIds.length - 1]; 

    // Update personIdToIndex
    personIdToIndex[personIds[key]] = key;

    // Decrease length of personIds array by 1
    personIds.length--;
    // Update personIdToIndex
    personIdToIndex[personIds[key]] = key;
  }
}

I won't mark this as the correct answer for now, because I still hope there's a more elegant solution.

Even though that's far from ideal (because it causes additional gas cost), this is how I do it now:

pragma solidity ^0.4.24;

contract MyContract {

  struct Person {
    uint age;
    uint size;
  }

  // Index of a person is its ID.
  Person[] persons;


  // The following holds a list of currently existing persons (without holes between the indexes)
  uint256[] personIds;

  // Holds the mapping from personID to its index in the above personIds array.
  mapping (uint256 => uint256) personIdToIndex;

  modifier personExists(uint256 _id) {
    uint256 index = personIdToIndex[_id]; // is 0 if not explicitly set
    require(personIds[index] == _id, "Person does not exist.");

    _;
  }

  event PersonAdded(uint indexed id, uint age, uint size);

  function addPerson(uint _age, uint _size) public {
    Person memory person = Person(_age, _size);
    id = persons.push(person) - 1;

    uint256 key = personIds.push(id) - 1;
    personIdToIndex[id] = key;

    emit PersonAdded(id, _age, _size)
  }

  function removePerson(uint _id) personExists(_id) public {
    delete persons[_id]

    // Reorganize index array and map
    uint256 key = personIdToIndex[_id];
    // Fill gap with last element of personIds
    personIds[key] = personIds[personIds.length - 1];
    // Decrease length of personIds array by 1
    personIds.length--;
    // Update personIdToIndex
    personIdToIndex[personIds[key]] = key;
  }
}

I won't mark this as the correct answer for now, because I still hope there's a more elegant solution.

Even though that's far from ideal (because it causes additional gas cost), this is how I do it now:

pragma solidity ^0.4.24;

contract MyContract {

  struct Person {
    uint age;
    uint size;
  }

  // Index of a person is its ID.
  Person[] persons;


  // The following holds a list of currently existing persons (without holes between the indexes)
  uint256[] personIds;

  // Holds the mapping from personID to its index in the above personIds array.
  mapping (uint256 => uint256) personIdToIndex;

  modifier personExists(uint256 _id) {
    uint256 index = personIdToIndex[_id]; // is 0 if not explicitly set
    require(personIds[index] == _id, "Person does not exist.");

    _;
  }

  event PersonAdded(uint indexed id, uint age, uint size);

  function addPerson(uint _age, uint _size) public {
    Person memory person = Person(_age, _size);
    id = persons.push(person) - 1;

    uint256 key = personIds.push(id) - 1;
    personIdToIndex[id] = key;

    emit PersonAdded(id, _age, _size)
  }

  function removePerson(uint _id) personExists(_id) public {
    delete persons[_id]

    // Reorganize index array and map
    uint256 key = personIdToIndex[_id]; 

    // Fill gap with last element of personIds
    personIds[key] = personIds[personIds.length - 1]; 

    // Update personIdToIndex
    personIdToIndex[personIds[key]] = key;

    // Decrease length of personIds array by 1
    personIds.length--;
  }
}

I won't mark this as the correct answer for now, because I still hope there's a more elegant solution.

added missing update of personIdToIndex array on remove
Source Link
haggis
  • 245
  • 1
  • 2
  • 10

Even though that's far from ideal (because it causes additional gas cost), this is how I do it now:

pragma solidity ^0.4.24;

contract MyContract {

  struct Person {
    uint age;
    uint size;
  }

  // Index of a person is its ID.
  Person[] persons;


  // The following holds a list of currently existing persons (without holes between the indexes)
  uint256[] personIds;

  // Holds the mapping from personID to its index in the above personIds array.
  mapping (uint256 => uint256) personIdToIndex;

  modifier personExists(uint256 _id) {
    uint256 index = personIdToIndex[_id]; // is 0 if not explicitly set
    require(personIds[index] == _id, "Person does not exist.");

    _;
  }

  event PersonAdded(uint indexed id, uint age, uint size);

  function addPerson(uint _age, uint _size) public {
    Person memory person = Person(_age, _size);
    id = persons.push(person) - 1;

    uint256 key = personIds.push(id) - 1;
    personIdToIndex[id] = key;

    emit PersonAdded(id, _age, _size)
  }

  function removePerson(uint _id) personExists(_id) public {
    delete persons[_id]

    // Reorganize index array and map
    uint256 key = personIdToIndex[_id];
    // Fill gap with last element of personIds
    personIds[key] = personIds[personIds.length - 1];
    // Decrease length of personIds array by 1
    personIds.length--;
    // Update personIdToIndex
    personIdToIndex[personIds[key]] = key;
  }
}

I won't mark this as the correct answer for now, because I still hope there's a more elegant solution.

Even though that's far from ideal (because it causes additional gas cost), this is how I do it now:

pragma solidity ^0.4.24;

contract MyContract {

  struct Person {
    uint age;
    uint size;
  }

  // Index of a person is its ID.
  Person[] persons;


  // The following holds a list of currently existing persons (without holes between the indexes)
  uint256[] personIds;

  // Holds the mapping from personID to its index in the above personIds array.
  mapping (uint256 => uint256) personIdToIndex;

  modifier personExists(uint256 _id) {
    uint256 index = personIdToIndex[_id]; // is 0 if not explicitly set
    require(personIds[index] == _id, "Person does not exist.");

    _;
  }

  event PersonAdded(uint indexed id, uint age, uint size);

  function addPerson(uint _age, uint _size) public {
    Person memory person = Person(_age, _size);
    id = persons.push(person) - 1;

    uint256 key = personIds.push(id) - 1;
    personIdToIndex[id] = key;

    emit PersonAdded(id, _age, _size)
  }

  function removePerson(uint _id) personExists(_id) public {
    delete persons[_id]

    // Reorganize index array and map
    uint256 key = personIdToIndex[_id];
    // Fill gap with last element of personIds
    personIds[key] = personIds[personIds.length - 1];
    // Decrease length of personIds array by 1
    personIds.length--;
  }
}

I won't mark this as the correct answer for now, because I still hope there's a more elegant solution.

Even though that's far from ideal (because it causes additional gas cost), this is how I do it now:

pragma solidity ^0.4.24;

contract MyContract {

  struct Person {
    uint age;
    uint size;
  }

  // Index of a person is its ID.
  Person[] persons;


  // The following holds a list of currently existing persons (without holes between the indexes)
  uint256[] personIds;

  // Holds the mapping from personID to its index in the above personIds array.
  mapping (uint256 => uint256) personIdToIndex;

  modifier personExists(uint256 _id) {
    uint256 index = personIdToIndex[_id]; // is 0 if not explicitly set
    require(personIds[index] == _id, "Person does not exist.");

    _;
  }

  event PersonAdded(uint indexed id, uint age, uint size);

  function addPerson(uint _age, uint _size) public {
    Person memory person = Person(_age, _size);
    id = persons.push(person) - 1;

    uint256 key = personIds.push(id) - 1;
    personIdToIndex[id] = key;

    emit PersonAdded(id, _age, _size)
  }

  function removePerson(uint _id) personExists(_id) public {
    delete persons[_id]

    // Reorganize index array and map
    uint256 key = personIdToIndex[_id];
    // Fill gap with last element of personIds
    personIds[key] = personIds[personIds.length - 1];
    // Decrease length of personIds array by 1
    personIds.length--;
    // Update personIdToIndex
    personIdToIndex[personIds[key]] = key;
  }
}

I won't mark this as the correct answer for now, because I still hope there's a more elegant solution.

Source Link
haggis
  • 245
  • 1
  • 2
  • 10

Even though that's far from ideal (because it causes additional gas cost), this is how I do it now:

pragma solidity ^0.4.24;

contract MyContract {

  struct Person {
    uint age;
    uint size;
  }

  // Index of a person is its ID.
  Person[] persons;


  // The following holds a list of currently existing persons (without holes between the indexes)
  uint256[] personIds;

  // Holds the mapping from personID to its index in the above personIds array.
  mapping (uint256 => uint256) personIdToIndex;

  modifier personExists(uint256 _id) {
    uint256 index = personIdToIndex[_id]; // is 0 if not explicitly set
    require(personIds[index] == _id, "Person does not exist.");

    _;
  }

  event PersonAdded(uint indexed id, uint age, uint size);

  function addPerson(uint _age, uint _size) public {
    Person memory person = Person(_age, _size);
    id = persons.push(person) - 1;

    uint256 key = personIds.push(id) - 1;
    personIdToIndex[id] = key;

    emit PersonAdded(id, _age, _size)
  }

  function removePerson(uint _id) personExists(_id) public {
    delete persons[_id]

    // Reorganize index array and map
    uint256 key = personIdToIndex[_id];
    // Fill gap with last element of personIds
    personIds[key] = personIds[personIds.length - 1];
    // Decrease length of personIds array by 1
    personIds.length--;
  }
}

I won't mark this as the correct answer for now, because I still hope there's a more elegant solution.