1

I'm trying to create a mapping whit this structure:

mapping(string => House) public houses;

where House is a Struct:

    struct House {
    address payable owner;
    uint256 base_price;
}

I already have an array where I store all the strings that I want in my mapping keys, lets say something like this:

string[] public cities = ["New York", "Las Vegas", "London", "Paris", "Moscow"];

The only exception is that my array is much longer (250 elements) and I wanted to know if it'd possible to create the mapping without looping through the array using something like a map function in javascript giving to all of the initial element the same starting Struct.

At the moment I'm doing it like this:

    for (uint i=0; i<cities.length; i++) {
        houses[cities[i]] = House(payable(0), 0.0005 ether, "");
    }

Is there a more efficient way of doing this? Thank you in advance.

0

The map from JavaScript is actually iterating to all the elements behind the scenes and applying the transformation you define, so it is equivalent to creating a manual loop in Solidity (for, while).

As for your specific case, perhaps you don't necessarily need to assign a default value. Any address without an initial assignment is already an address(0). On the other hand, a uint by default is 0. Therefore, whenever you access any of the data in struct House, you could check if the price value is 0, and if so, you could assign the 0.0005 ether at that time or directly with the new value.

In summary, you can assign the base_price as you see during the contract execution, instead of assigning a default price to all cities at the beginning (and consuming quite a lot of gas).

1
  • This is a clever way, I'll try it but I think it could work for me. – Voldo Mar 10 at 8:32
1

Like this?

// SPDX-License-Identifier: UNLICENSED

pragma solidity 0.7.6;

contract Mapping {
    
    struct Struct {
        bool foo;
    }
    
    mapping(string => Struct) map;

}

As a sidenote, I would be inclined to map from bytes32 instead of from strings, where the key is a hash that is expected to be unique in all cases.

I'm not certain, but your question gave me the impression that you are a little unsure about how to separate layout and process. The code above establishes a layout but it says nothing about the process of populating it.

This bit:

for (uint i=0; i<cities.length; i++) {
   houses[cities[i]] = House(payable(0), 0.0005 ether, "");
}

This is a valid way to fill it up, provided that cities.length will never exceed a practical limit (block gasLimit). In other words, it's usually a good idea to also present a function that will insert exactly 1 instead of a list.

As a general heuristic, iteration in a contract should be viewed with suspicion. It might indicate a sub-optimal separation of concerns.

Just some thoughts that might help: https://blog.b9lab.com/getting-loopy-with-solidity-1d51794622ad

Hope it helps.

1
  • In my case this for loop will be executed in the costructor method so only when I deploy the contract and the array lenght is fixed at roughly 250 elements. I just wanted to know if there's a better way of populating the mapping instead of using a for loop. – Voldo Mar 10 at 8:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.