Arrays, Structs & Mappings


#1

Welcome to the thread about Arrays, Structs & Mappings in Ethereum. Here you can discuss everything about this chapter.


#2

Ohh duuuuuddeeee, I’m the first comment. :sunglasses:
I feel so powerful.


#3

Hi Filip,

In the example where you have mapping ownerToDog[owner]=id; if the same owner (address) input more than 1 dog, only the latest dog id will be retrieved. In order to retrieve all the dogs that belong to a certain owner, seems like you would need map: owner => an array of id’s. Correct?

Thanks.


#4

Lets push it to the limits.

Here is a progression of the code.

This is leading up to a profile that can be used for people. (Next assignment foreshadow)

pragma solidity^0.4.0;


//Create a contract named DogContract
contract DogContract{
   //Create a struct named Dog with a string name 
   //and an unassigned integer age.
   struct Dog {
       string name;
       uint age;
       string breed;
   }
   //Dog is it is a struct and thus can be called as an array,
   //The Dog Array is named dogs.
   Dog[] dogs;
   
   // Keep Track of the owner by using a mapping structure to have key point to an
   //unassigned integer for the index position in the array.
   mapping(address => uint) ownerToDog;
   
   
   //Setter function to add a dog. The input parameters are with a string name 
   //and an unassigned integer age
   function addDog(string _name, uint _age, string _breed){
       
       //create owner variable of type address equat to the transactor. 
       address owner = msg.sender;
       
       // Push input for the transactor into the dogs array. 
       //This will return the id of the dog in the list (returns the index possition in the array)
       // therefore we stroe it as an unsigned integer named id
       uint id = dogs.push(Dog(_name, _age, _breed));
       
       
       ownerToDog[owner]=id;
   }
   function getDogName() view returns (string){
       address owner = msg.sender;
       uint id = ownerToDog[owner];
       return dogs[id - 1].name;
   }
   function getDogAge() view returns (uint){
       address owner = msg.sender;
       uint id = ownerToDog[owner];
       return dogs[id - 1].age;
   }
   function getDogBreed() view returns (string){
       address owner = msg.sender;
       uint id = ownerToDog[owner];
       return dogs[id - 1].breed;
   }
}

#5

Alright here is the Average Age in the group.

pragma solidity^0.4.0;

contract Profile{
   
   struct Person{
       string name;
       uint age;
   }
   Person[] people;
   
   mapping(address => uint) public ownerToProfile;
   
   function setPerson(string _name, uint _age){
       address owner = msg.sender;
       uint id = people.push(Person(_name, _age));
       ownerToProfile[owner] = id;
   }
   function getAvgAge() view returns (uint){
       uint sumAges;
       for (uint i=0; i<people.length; i++){
           sumAges += people[i].age;
       }
       return (sumAges/people.length);
   }
}

Test net live on Rinkeby at the contract address

0xbdf0f34c3cba52f714de64d5d8ede6957bdd1c7c

https://rinkeby.etherscan.io/tx/0xf3d2b8e697a5483a7290172bbc439043d58119ebf8d1c9660008a23b1c9b4610

Copy the source code into your remix browser, connect metamask to Rinkeby, and instead of Deploying your own instance, put the contract address in Load contract from Address and click At Address.

This will load the contract from the Test Net and allow you to submit your response. Remember when submitting setPerson you must use parenthesis for string input.

For example

"Guactoshi", 27

would be my imput for setPerson.


#6

Question - does solidity automatically initialise all uint variables to zero if not explicitly specified?


#7

Yes, you are correct. Good point! That is a limitation that could be resolved with the mapping pointing to the array. For better behaviour you could also add a “require” check to see if the owner owns any previous dog to prevent the loss of a dog :disappointed_relieved:


#8

Yes, that’s right. uint will initialize to 0 and bool to false etc. They all have what’s called a zero state to begin with.


#9

I am reviewing the lecture over and over.
I’ve got the arrays and structs down. But mapping is…:unamused:

I think it’s the syntax.

//Update

Average age :

pragma solidity ^0.4.0;

contract AverageAge
{
struct Per
{
string name;
uint age;
}

Per[] people;

function setPerson(string _name, uint _age)
{
    people.push(Per(_name,_age));
}

function getAve() view returns(uint)
{
    uint ave = 0;
    for(uint count = 0; count<people.length; count++)
    {
        ave = ave + people[count].age;
        
    }
    
    return ave/count;
    
    
}

}

// June 22nd…UPDATE :smile:
Finally understand mappings and how to use them properly. It took me a few days.
I did it in parts. First understand how it’s created, then how it’s used in the setter, then the getter.


#10

You’re not alone :stuck_out_tongue: I too need to rewatch it a few times.


#11

I am not sure why I am getting this error.

pragma solidity ^0.4.0;

contract Persons{

struct People{
    
    string name;
    uint age;
    
}

People[] listOfPeople;

function addPerson(string _name, uint _age){
    listOfPeople.push(People(_name, _age));
}

function getAverageAge() view returns(int){
    
    uint total = 0;
    
    for(uint count = 0; count < listOfPeople.length; count++){
        total = total + People[count].age;
    }
    
    return total/count;
}

}

browser/Exercise2.sol:23:36: TypeError: Integer constant expected.
total = total + People[count].age;
. . . . . . . . . . . . . . . . . .^—^


#13

Nevermind. I needed to have “listOfPeople[count].age” instead of “People[count].age”.


#14

IM following you on the ethereum course but when i try to deploy my dog contract i receie following error when trying to deploy following code

pragma solidity ^0.4.0;

contract DogContract{

string[] dogs = ["Paul", "bob", "jimmy", "rudi"];

function addDog(string _name){
    dogs.push(_name);
}

function getDog(uint _id) returns (string){
    return dogs[1];
}

}

THis is the error message:
creation of DogContract pending…
[vm]from:0xca3…a733cto:DogContract.(constructor)value:0 weidata:0x608…50029logs:0hash:0x7e0…569fe


#15

Hi @yayo,

That is not an error message that you have posted there. It just says that the creation of the contract is pending. Is there any other message in the console? Could you maybe screenshot what it looks like when you try to create?


#17

The contract looks deployed to me. Look at the bottom left at the screen. There you will see DogContract and it’s two methods.


#20

so uint can also be used as a variable!?
i thought uint only describes a “state” - that it cant be negative


#21

can Someone explain me deeper this line? : msg.sender


#22

@yayo uint is a data type and it can be used like the way you use int…

E.g.

uint age = 25;

The difference is that uint holds positive numbers.

@Danny1
Remember that in JS array.length returns a number equal to the amount of elements in an array.
In the same way msg.sender returns the address of the one that called the function or contract.
So based on that I would say that when a function is called the action produces a variable and sender is one of it’s properties. At least this is how I wrapped my head around it.


#23

Hi Filip,
In your code here:
pragma solidity^0.4.0;

contract DogContract{

struct Dog {
    string name;
    uint age;
}

Dog[] dogs;
mapping(address => uint) ownerToDog;

event addedDog(address owner, string name, uint dogId);

function addDog(string _name, uint _age) internal {
    address owner = msg.sender;
    uint id = dogs.push(Dog(_name, _age));
    ownerToDog[owner] = id;
    addedDog(owner, _name, id);
}

function getDog() returns (string) {
    address owner = msg.sender;
    uint id = ownerToDog[owner];
    return dogs[id-1].name;
}

}

what does the key word “internal” do exactly ?


#24

The keyword “internal” changes the visibility of the function.

So, by default the contract can be seen internally as well externally. Internally means that when we do inheritance one contract can see the functions of another. That is when we use the keyword “is”. Example(contract Dog is dogKennel). If we set the functions in Dog to “internal” they can only be accessed by dogKennel.

Externally means that it can be accessed via the getter and setter buttons for example.

So that’s why when we use “internal” the button on the right disappeared and we were no longer able to interact with it from the console. The only way to access it now is through another contract(or function) internally.

On the other hand if we made Dog “external” the functions would not be available to dogKennel however we would be able to interact with it from the outside( e.g via the console on the right).

// I am aware that it may not be precisely as I explained it but that’s the gist of things.