Anyone know how to delete an element in a array? Is there any built in method to do that?
If not, does anyone know of how to implement such a method?
Ethereum Stack Exchange is a question and answer site for users of Ethereum, the decentralized application platform and smart contract enabled blockchain. It only takes a minute to sign up.
Sign up to join this communityAnyone know how to delete an element in a array? Is there any built in method to do that?
If not, does anyone know of how to implement such a method?
Use the delete
operator to delete the element:
delete array[index];
If you don't want to leave a gap, you need to move each element manually:
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;
}
}
If you don't care about the order, you can also just copy the last element into the empty spot, then delete the last element.
function remove(uint[] array,uint index) returns(uint[]) {
gives me Error: Expression has to be an lvalue. array.length--;
Also , does that method can be adapted to work on array of all types ( struct , etc ) ?
delete
doesn't really make sense in mappings.
Feb 21, 2016 at 2:41
delete array[array.length-1];
is redundant. Moreover it adds 5000 gas to the transaction since gas refund applies only in the case when storage is reset from non-zero to zero value. If it's set from zero to zero (added by compiler) it costs 5000 gas.
Feb 11, 2018 at 20:02
This constant operation works without preserving order:
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();
}
To preserve order on recall without incurring the gas cost of shifting right-of-gap values, you'll need an additional mapping between each element's index to its successor's index that you need to maintain during insertion and deletion: mapping(uint => uint) private indexAfter;
Small optimisation to Tjaden Hess' answer:
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;
}
}
I removed the line delete array[array.length-1];
before array.length--;
. This makes the function cheaper by 5000 gas. The compiler will automatically clean up unoccupied slots when array length is decreased. Double storage resetting adds 5000 gas.
Most of the previous answers directly modify the array length to reduce its length.
Since Solidity 0.6.0 this is no longer possible
Member-access to length of arrays is now always read-only, even for storage arrays. It is no longer possible to resize storage arrays assigning a new value to their length. Use push(), push(value) or pop() instead, or assign a full array, which will of course overwrite existing content. The reason behind this is to prevent storage collisions by gigantic storage arrays.
https://docs.soliditylang.org/en/v0.6.2/060-breaking-changes.html
You can fix medvedev1088's answer with:
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;
}
}
Notice: array.pop();
instead of array.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;
}
}
delete a assigns the initial value for the type to a. I.e. for integers it is equivalent to a = 0, but it can also be used on arrays, where it assigns a dynamic array of length zero or a static array of the same length with all elements reset. For structs, it assigns a struct with all members reset.
> I have implemented it, may be helpful to understand by this simple example
**
And if we remove the element using index it will not leave the gap.
**
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;
}
}
A solution that consumes a bit more gas compared to others.
// 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;
}