Кто-нибудь знает, как удалить элемент в массиве? Есть ли встроенный метод для этого?
Если нет, кто-нибудь знает, как реализовать такой метод?
Используйте delete
оператор для удаления элемента:
delete array[index];
Если вы не хотите оставлять пробел, вам нужно перемещать каждый элемент вручную:
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;
}
}
Если вас не волнует порядок, вы также можете просто скопировать последний элемент в пустое место, а затем удалить последний элемент.
function remove(uint[] array,uint index) returns(uint[]) {
дает мне Error: Expression has to be an lvalue. array.length--;
Кроме того, этот метод может быть адаптирован для работы с массивом всех типов (структуры и т.д.)?delete
в сопоставлениях он не имеет особого смысла.delete array[array.length-1];
лишняя. Кроме того, он добавляет 5000 газа к транзакции, так как возврат газа применяется только в случае, когда хранилище сбрасывается с ненулевого значения на нулевое. Если он установлен от нуля до нуля (добавлено компилятором), он стоит 5000 газа.Эта постоянная операция работает без сохранения порядка:
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();
}
Чтобы сохранить порядок при отзыве, не неся затраты газа на сдвиг значений справа от промежутка, вам потребуется дополнительное сопоставление между индексом каждого элемента с индексом его преемника, которое вам необходимо поддерживать во время вставки и удаления:mapping(uint => uint) private indexAfter;
Небольшая оптимизация ответа Тьядена Хесса:
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;
}
}
Я удалил строку delete array[array.length-1];
раньше array.length--;
. Это удешевляет функцию на 5000 газа. Компилятор автоматически очищает незанятые слоты при уменьшении длины массива. Двойной сброс хранилища добавляет 5000 газа.
Большинство предыдущих ответов напрямую изменяют длину массива, чтобы уменьшить его длину.
Начиная с Solidity 0.6.0 это больше невозможно
Доступ членов к массивам длины теперь всегда доступен только для чтения, даже для массивов хранения. Больше нельзя изменять размер массивов хранения, присваивая новое значение их длине. Вместо этого используйте push(), push(value) или pop() или назначьте полный массив, который, конечно, перезапишет существующее содержимое. Причина этого заключается в предотвращении коллизий хранения из-за гигантских массивов хранения.
https://docs.soliditylang.org/en/v0.6.2/060-breaking-changes.html
Вы можете исправить ответ medvedev1088 с помощью:
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;
}
}
Обратите внимание: array.pop();
вместо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 присваивает начальное значение типа a. Т.е. для целых чисел это эквивалентно a = 0, но его также можно использовать для массивов, где он присваивает динамический массив нулевой длины или статический массив той же длины со сбросом всех элементов. Для структур он назначает структуру со всеми сброшенными элементами.
> Я реализовал это, может быть полезно понять этот простой пример
**
И если мы удалим элемент с помощью индекса, он не оставит пробел.
**
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;
}
}
Решение, которое потребляет немного больше газа по сравнению с другими.
// 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;
}
Тьяден Хесс
пользователь697