1

I see that push and pop methods are not available for memory arrays in solidity. I have a code below where I need to return an array of struct satisfying condition as shown below. How do we do this, if we don't know the array length beforehand because as of now I'm declaring an array with the maximum size possible and returning the data as well as size that contains the relevant information for me.
How do we do this using memory arrays or is it not possible?

function getRegisteredDoctorsByDept(string memory deptName) public view returns(DoctorDetails [] memory, uint) {
   DoctorDetails[] memory doctorArray = new DoctorDetails[](doctorAddress.length);
   uint length = 0;
   
   for(uint i = 0; i < doctorAddress.length; i++) {
     if (keccak256(abi.encodePacked(doctors[doctorAddress[i]].department)) == keccak256(abi.encodePacked(deptName))) {
       // doctorArray.push(doctorAddress[i]);
       doctorArray[i] = (doctors[doctorAddress[i]]);
       length = i;
     }
   }
   return (doctorArray, length);
 }

3 Answers 3

0
using a dynamic array in memory

You also iterate thorugh the doctorAddresses to count the number of addresses, then create a dynamic array with the length as count. And iterate through doctorAddresses again to fill the array:

function getRegisteredDoctorsByDept(string memory deptName) public view returns (DoctorDetails[] memory) {
    uint count = 0;
    for (uint i = 0; i < doctorAddress.length; i++) {
        if (keccak256(abi.encodePacked(doctors[doctorAddress[i]].department)) == keccak256(abi.encodePacked(deptName))) {
            count++;
        }
    }

    DoctorDetails[] memory doctorArray = new DoctorDetails[](count);
    uint i = 0;
    for (uint j = 0; j < doctorAddress.length; j++) {
        if (keccak256(abi.encodePacked(doctors[doctorAddress[j]].department)) == keccak256(abi.encodePacked(deptName))) {
            doctorArray[i] = doctors[doctorAddress[j]];
            i++;
        }
    }

    return doctorArray;
}

set length to count in memory array

Another potential way you could do it with memory array for the doctors that match deptName you can use assembly to set the length of the array to count.

function getRegisteredDoctorsByDept(string memory deptName) public view returns (DoctorDetails[] memory) {
    DoctorDetails[] memory doctorArray = new DoctorDetails[](doctorAddress.length);
    uint count = 0;

    for (uint i = 0; i < doctorAddress.length; i++) {
        if (keccak256(abi.encodePacked(doctors[doctorAddress[i]].department)) == keccak256(abi.encodePacked(deptName))) {
            doctorArray[count] = doctors[doctorAddress[i]];
            count++;
        }
    }

    // Resize the array length to count
    if (count < doctorArray.length) {
        assembly {
            mstore(doctorArray, count)
        }
    }

    return doctorArray;
}

using local storage variable

Even though the question is about memory arrays, just to add: another approach without declaring an array with a maximum size might still be be use a dynamic array in storage and push the relevant structs into it.

function getRegisteredDoctorsByDept(string memory deptName) public view returns (DoctorDetails[] memory) {
    DoctorDetails[] storage doctorArray;
    
    for (uint i = 0; i < doctorAddress.length; i++) {
        if (keccak256(abi.encodePacked(doctors[doctorAddress[i]].department)) == keccak256(abi.encodePacked(deptName))) {
            doctorArray.push(doctors[doctorAddress[i]]);
        }
    }
    
    return doctorArray;
}

using mapping outside of function

Or you use a mapping to store the doctorsByDept, push into the array when adding them, and the let getRegisteredDoctorsByDept return the doctorsByDept via deptName:

mapping(string => DoctorDetails[]) doctorsByDept;

function addDoctor(string memory deptName, string memory doctorName, uint doctorAge) public {
   DoctorDetails memory newDoctor = DoctorDetails(doctorName, deptName, doctorAge);
   doctorsByDept[deptName].push(newDoctor);
}

function getRegisteredDoctorsByDept(string memory deptName) public view returns(DoctorDetails[] storage) {
   return doctorsByDept[deptName];
}
2
  • Great.. Thanks @timsntech Feb 20, 2023 at 8:01
  • You're welcome!
    – timsntech
    Feb 20, 2023 at 18:09
0

Try returns (address[] memory)

Example :

function FunctionName(address a,address b) private pure returns (address[] memory) {
    address[] memory path = new address[](2);
    path[0] = a;
    path[1] = b;

return path;
}
0

Better use global storage variable for the doctorArray :

contract .......{
DoctorDetails[] private doctorArray;

function getRegisteredDoctorsByDept(string memory deptName) public view returns(DoctorDetails [] memory, uint) {

    //remove all elements from doctorArray somehow:
    for(uint i =0; i<doctorArray.lenth; i++) {
        doctorArray.pop();
    }
    for(uint i = 0; i < doctorAddress.length; i++) {
        if (keccak256(abi.encodePacked(doctors[doctorAddress[i]].department)) == keccak256(abi.encodePacked(deptName))) {
        doctorArray.push(doctorAddress[i]);
        length = i;
        }
    }
    return (doctorArray, doctorArray.length);
}

OR first count the resulting array size:

function getRegisteredDoctorsByDept(string memory deptName) public view returns(DoctorDetails [] memory, uint) {
    uint length = 0;

    for(uint i = 0; i < doctorAddress.length; i++) {
        if (keccak256(abi.encodePacked(doctors[doctorAddress[i]].department)) == keccak256(abi.encodePacked(deptName))) {
        length++;
        }
    }

    DoctorDetails[] memory doctorArray = new DoctorDetails[](length);
    
    uint resultingArrayIdx = 0;
    for(uint i = 0; i < doctorAddress.length; i++) {
        if (keccak256(abi.encodePacked(doctors[doctorAddress[i]].department)) == keccak256(abi.encodePacked(deptName))) {
            doctorArray[resultingArrayIdx++] = (doctors[doctorAddress[i]]);
        }
    }
    return (doctorArray, length);
}
1
  • Sorry, didn't see @timsntech answer, it looks the same Feb 19, 2023 at 18:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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