Remove an element in array but the struct is still inside - ethereum

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

You will have to move every element after that so that you don't leave a "gap". There is not a way to delete and rearrange the elements unless you do it yourself.

Try this code
contract test {
struct Prodotto {
string titolo;
address owner_address;
}
Prodotto[] public prodotti;
constructor() public {
for (uint i = 0; i < 5; i++) {
prodotti.push(Prodotto({
titolo: 'one more',
owner_address: address(i)
}));
}
}
function remove(uint index) public {
for (uint i = index; i < prodotti.length-1; i++) {
prodotti[i] = prodotti[i+1];
}
delete prodotti[prodotti.length-1];
prodotti.length--;
}
function check() public view returns(uint256) { return prodotti.length; }
}

Related

For/If Loop has no errors but does not push the value to the array

I am trying to create a whitelist. I've used a for and if loop to check if the msg.sender already exists in the array. When the whitelist() function is run, no errors are returned, but when I run check(), it tells me the address doesn't exist in the array, same thing with directing fetching the array.
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract SelfWhitelist {
address[] public addressWhitelist;
function whitelist() public returns(string memory) {
for(uint i = 0; i < addressWhitelist.length; i++) {
if(addressWhitelist[i] != msg.sender) {
addressWhitelist.push(msg.sender);
return "Whitelisted!";
}
}
return "Already whitelisted!";
}
function check() public view returns (bool){
for(uint i = 0; i < addressWhitelist.length; i++){
if(addressWhitelist[i] == msg.sender)
return true;
}
return false;
}
}
I added this block of code to check for duplicate entries in the array.
for(uint i = 0; i < addressWhitelist.length; i++) {
if(addressWhitelist[i] != msg.sender) {
addressWhitelist.push(msg.sender);
return "Whitelisted!";
}
Expected for no errors and my address being pushed to the array.
The code ran without errors, but nothing was added to the array.
I would use mapping type to hold the whitelisted addresses, then you don't have to loop over the array
contract SelfWhitelist {
mapping(address => bool) public addressWhitelist;
function whitelist() public returns(string memory) {
if (check()) {
return "Already whitelisted!";
}
addressWhitelist[msg.sender] = true;
return "Whitelisted!";
}
function check() public view returns (bool) {
return addressWhitelist[msg.sender];
}
}
And in your code, seems you have logical issues:
for(uint i = 0; i < addressWhitelist.length; i++) {
if(addressWhitelist[i] != msg.sender) {
addressWhitelist.push(msg.sender);
return "Whitelisted!";
}
}
if the array is empty, the loop never executes, so nothing will be added
if the first item is not msg.sender, msg.sender will be whitelisted, even though it might be already whitelisted.

Solidity: Retrieving values of Array of Structs in Mapping

I have some solidity code where I am attempting to gather the ids which are a value stored on a Struct. I have a mapping where the key is an address, and the value is an array of Structs. Whenever I execute the getMediaByAddress function I get an invalid OpCode error. Any help would be greatly appreciated.
pragma solidity ^0.4.24;
contract MediaGallery {
address owner;
uint counter;
struct MediaAsset {
uint id;
string name;
address author;
uint createDate;
string[] tags;
string mediaHash;
}
mapping(address => MediaAsset[]) public mediaDatabase;
constructor () {
owner = msg.sender;
}
function addMedia(string _name, string _mediaHash) public returns (bool success) {
MediaAsset memory currentMedia;
currentMedia.id = counter;
currentMedia.name = _name;
currentMedia.author = msg.sender;
currentMedia.createDate = now;
currentMedia.mediaHash = _mediaHash;
mediaDatabase[msg.sender].push(currentMedia);
return true;
}
function addTag(uint _id, string _tag) public returns (bool success) {
mediaDatabase[msg.sender][_id].tags.push(_tag);
return true;
}
function getMediaByAddress(address _user) public view returns (uint[]) {
uint[] memory mediaAssetIds = new uint[](mediaDatabase[_user].length);
uint numberOfMediaAssets = 0;
for(uint i = 1; i <= mediaDatabase[_user].length; i++) {
mediaAssetIds[numberOfMediaAssets] = mediaDatabase[_user][i].id;
numberOfMediaAssets++;
}
return mediaAssetIds;
}
}
You're trying to read past the end of the array. Your loop variable i has an off-by-one error. Its greatest value is mediaDatabase[_user].length, which is 1 past the end of the array. Try this instead:
for (uint i = 0; i < mediaDatabase[_user].length; i++) {

null pointer exception at run time

This is my first post here. I am trying to create a singly link list. I am using AtEnd and AtStart methods to insert values at the end or in the beginning of the list and using display method to print all the values. The insertion methods seems to be working fine (at least I think so) but whenever I call display method it shows only the first value and then there is a null pointer exception. For example when I run this code I see only 9 and then there is the NPE despite the fact that I have put a check on the display method for "not null".
class node {
private int data;
private node next;
node() {
}
node(int data) {
this.data = data;
this.next = null;
}
public int getData() {
return data;
}
public void setData(int data) {
this.data=data;
}
public node getNext() {
return next;
}
public void setNext(node next) {
this.next = next;
}
}
public class list extends node {
node head;
list() {
}
public void AtStart(int val) {
node n = new node(val);
if (head == null) {
head=n;
} else {
n.setNext(head);
int temp = head.getData();
head.setData(val);
n.setData(temp);
//n = head;
}
}
public void AtEnd(int val) {
if (head == null) {
node n = new node(val);
head = n;
} else {
node t = head;
for(; t.getNext() != null; ) {
if(t.getNext() == null) {
t.setNext(new node (val));
}
t = t.getNext();
}
}
}
public void display() {
node t = head;
for(; t.getNext() == null;) {
if (t !=null) {
System.out.println(t.getData());
t = t.getNext();
}
}
}
}
public static void main(String args[]) {
list l = new list();
l.AtStart(16);
l.AtEnd(6);
l.AtEnd(36);
l.AtStart(9);
l.AtEnd(22);
l.display();
}
i dont get what your AtStart function does, it should be much simpler:
public void AtStart(int val){
if(head==null){
head=n;
}
else{
head.setnext(head);
head.setData(val);
}
}

as3: How to create a custom iterator

I am trying to create custom iterator element. The class itself is below.
public class ArrayBasedIterator implements IteratorInterface
{
// Holds Array of elements which are iterated
private var _container:Array;
// Holds current index
private var _index:uint = 0;
public function ArrayBasedIterator(data:Array)
{
if (!data)
throw new Error("Cannot create iterator for null data");
_container = data;
}
/**
* Returns next node if it exists, null otherwise*/
public function next():TreeNode
{
if (_index > _container.length )
{
return null;
}
else {
_index += 1;
}
//TODO: implement function
return _container[_index];
}
/**
* Returns prev node if it exists, null otherwise*/
public function prev():TreeNode
{
if (_index < 0)
{
return null
}
else {
_index -= 1;
}
//TODO: implement function
return _container[_index];
}
public function len():int
{
return _container.length;
}
}
The question is. In case I have such iterator over some elements, would it be possible to use for .... in structure? What do I need to change to use it? (Except using just array instead of iterator of course)
If you want to use for ... in, you'll need to subclass Proxy and override the appropriate methods:
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/utils/Proxy.html

Problem with a property name of an object

I have this function:
private function returnFees(row:Object,name:String):int
{
var fee:int;
for each(var obj:Object in row)
{
if(obj==name)
{
//fee=obj as int;
}
}
return fee;
}
I want to compare the name of properties to the 'name'. But in this code the 'obj' is giving me the values of properties not the name.
Any ideas? thank you
It's not a for each you have to use but a simple for. for each will give you the values and for the property name :
private function returnFees(row:Object,name:String):int {
var fee:int;
for (var rowName:String in row) {
if(rowName == name) {
//fee=obj as int;
}
}
return fee;
}