Solidity Arrays – Most Efficient Way to Compare Items in Different Arrays

arraysblockchainsoliditystorage

Within a Solidity Smart Contract, I have 2 arrays that need to be compared. I would like the output to be 3 different arrays that can be used for other logic within the contract.

Example of the arrays:

contract myLists {

    string[5] public listOne = ['AAA','BBB','CCC','DDD','EEE'];
    string[5] public listTwo = ['AAA','BBB','DDD','FFF','GGG'];

}

The outputs should be:

#Output 1: items in listTwo that do not exist in listOne   
string[] public output1['FFF','GGG']
#Output 2: items in listTwo that exist in listOne
string[] public output2['AAA','BBB','DDD']
#Output 3: items in listOne that do not exist in listTwo
string[] public output3['CCC','EEE']

From all my research, it seems array functionality is quite limited in Solidity and the only way may be a for loop.

What is the most gas efficient way to achieve this with arrays. Alternatively, is there a more efficient approach using a different method of storage e.g. Structs?

Thanks.

Best Answer

I've probably made some minor mistakes here but you get the jist of it. Use keccak256(abi.encodePacked("ABC")) to be able to compare strings. Then loop through one element of list2 at a time and compare that to all the elements in list1, when it sees an element that is the same, it adds that to the new list, breaks out of the inner loop and goes to the next element in list2 and compares that to all elements in list1.. and so on.


    //Output: items in listTwo that exist in listOne
    function compare() public view returns(string[] memory) {
        // write to memory to save gas when looping through
        string[5] memory list1 = listOne; 
        string[5] memory list2 = listTwo;

        string[] memory l2Inl1;
        uint nonce;
        for(uint i; i < 5; i++){
            for(uint j; j < 5; j++){
                if(keccak256(abi.encodePacked(list2[i])) == keccak256(abi.encodePacked(list1[j]))){
                    l2Inl1[nonce] = list2[i];
                    nonce++;
                    break
                }
            } 
        }
        return l2Inl1;
    }

You would need to construct something like this for each output that you need. Depending on what chain you run this, the gas cost of running keccak256(abi.encodePacked()) on every string might get costly. I would consider doing this off chain. Or first converting the strings to (or from the start using) a list of bytes, which you can compare. However, converting them back might return unexpected results, it all depends on your use case, which I don't know. But This should hopefully give you some ideas at least!

Related Topic