1

I have this contract with an array of structs:

pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;

contract Tickets {
  struct Ticket {
    uint id;
    int val;
  }

  Ticket[] tickets;

  function addTicket(uint id, int val) public returns(bool success) {
    Ticket memory newTicket;
    newTicket.id = id;
    newTicket.val = val;
    tickets.push(newTicket);

    return true;
  }

  function getTicket(uint id) public view returns(Ticket memory) {
    uint index;

    for(uint i = 0; i<tickets.length; i++){
      if (tickets[i].id == id) {
        index = i;
        break;
      }
    }

    Ticket memory t = tickets[index];

    return t;
  }

  function findTickets(int val) public view returns(Ticket[] memory) {
    Ticket[] memory result;

    for(uint i = 0; i<tickets.length; i++){
      if (tickets[i].val == val) {
        result.push(tickets[i]); // HERE IS THE ERROR
      }
    }

    return result;
  }
}

I need to returns a filtered by val array but when I buil this code: result.push(tickets[i].id); it throw this error:

TypeError: Member "push" is not available in struct Tickets.Ticket memory[] memory outside of storage.

How I can implement the filter without using push ?

1

Instead of using dynamic sized array, consider using mappings with a running counter. I would implement this contract as follows:

pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;

contract Tickets {

  struct Ticket {
    uint id;
    int val;
  }

  mapping(uint => Ticket) tickets;
  uint ticketCount;


  function addTicket(uint id, int val) public returns(bool success) {
    tickets[ticketCount] = Ticket({
        id: id,
        val: val
    });
    ticketCount += 1;

    success = true;
  }

  function getTicket(uint id) public view returns(Ticket memory) {
    for(uint i = 0; i<ticketCount; i++){
      if (tickets[i].id == id) {
        return tickets[i];
      }
    }
  }

  function findTickets(int val) public view returns(Ticket[] memory filteredTickets) {
    Ticket[] memory ticketsTemp = new Ticket[](ticketCount);
    uint count;
    for(uint i = 0; i<ticketCount; i++){
      if (tickets[i].val == val) {
        ticketsTemp[count] = tickets[i];
        count += 1;
      }
    }

    filteredTickets = new Ticket[](count);
    for(uint i = 0; i<count; i++){
      filteredTickets[i] = ticketsTemp[i];
    }

  }
}
| improve this answer | |
3

Taking @Newti 's answer into consideration.. if you need to filter your tickets by val, you could also just create a mapping just for that.

mapping(int => Ticket[]) filterByVal; // Val -> Ticket[]

Then, on the addTicket(), you would also have to push the new Ticket to the map.

| improve this answer | |

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.