Is there a pop functionality for solidity arrays?
Update 2-19-2019: As Joel pointed out below, pop
has been added to built-in array support. See https://solidity.readthedocs.io/en/v0.5.4/types.html#array-members. Leaving original answer on here in case others are using older versions of Solidity.
There is no pop function in Solidity. You have a few options you can consider for maintaining your array.
Delete & Leave Gaps
The simplest solution is to just delete
the element at a specific index:
string element = myArray[index];
delete myArray[index];
return element;
However, this will NOT shift the elements in your array and will leave an element of "string 0" in your array. To check this element, you would use
if(bytes(myArray[index]).length > 0) ...
Swap & Delete
If you don't care about order in your array, you can swap the element with the last element in your array and then delete:
string element = myArray[index];
myArray[index] = myArray[myArray.length - 1];
delete myArray[myArray.length - 1];
myArray.length--;
return element;
Delete With Shift
If order in your array is important, you can delete the element then shift all remaining elements to the left.
string element = myArray[index];
for (uint i = index; i < myArray.length - 1; i++) {
myArray[i] = myArray[i + 1];
}
delete myArray[myArray.length - 1];
myArray.length--;
return element;
Note that this will be the most expensive of the options. If your array is very long, you will have high gas usage.
Correlating with @Jedsada's suggestion, here is a version as a library:
pragma solidity ^0.4.24;
library StackLib {
using StackLib for Stack;
struct Stack {
uint[] _items;
}
function pushElement(Stack storage self, uint element) internal returns (bool) {
self._items.push(element);
}
function popElement(Stack storage self) internal returns (uint) {
uint element = self.peek();
if (self.size() > 0)
delete self._items[self.size() - 1];
return element;
}
function peek(Stack storage self) internal returns (uint) {
uint value;
if (self.size() > 0)
value = self._items[self.size() - 1];
return value;
}
function size(Stack storage self) internal returns (uint8) {
return self.size();
}
}
Example usage (Important note: You can't use popElement
and return the value to a client. That method changes state and should only be used within a transaction.):
contract Test {
using StackLib for StackLib.Stack;
StackLib.Stack numbers;
function add(uint v) public {
numbers.pushElement(v);
}
function doSomething() public {
for (uint8 i = 0; i < numbers.size(); i++) {
uint curNum = numbers.popElement();
// do something with curNum
}
}
}
Additional note: Unfortunately, var
has been deprecated since 0.4.20 and there is no replacement for generics. You have to customize for a specific type.
Yes there is, as of v0.5.0 (details here):
Dynamic storage arrays and bytes (not string) have a member function called pop that you can use to remove an element from the end of the array. This also implicitly calls :ref:delete on the removed element.
You can try...
pragma solidity ^0.4.17;
contract TestArray {
uint[] public items;
constructor () public {
items.push(1);
items.push(2);
items.push(3);
items.push(4);
}
function pushElement(uint value) public {
items.push(value);
}
function popElement() public returns (uint []){
delete items[items.length-1];
items.length--;
return items;
}
function getArrayLength() public view returns (uint) {
return items.length;
}
function getFirstElement() public view returns (uint) {
return items[0];
}
function getAllElement() public view returns (uint[]) {
return items;
}
}