'Is there an efficient way to join an array of strings into a single string in Solidity?
My goal is to write a function that takes an array of strings, and returns a single string containing all of the input strings combined.
For example, in Python this could be done this way:
result = ''.join(['hello', 'solidity', 'world']) # hellosolidityworld
My current implementation doesn't seem efficient at all:
function concat(string[] memory words) internal pure returns (string memory) {
// calculate output length
uint256 bytesLength;
for (uint256 i = 0; i < words.length; i++) {
bytesLength += bytes(words[i]).length;
}
bytes memory output = new bytes(bytesLength);
uint256 currentByte;
for (uint256 i = 0; i < words.length; i++) {
bytes memory bytesWord = bytes(words[i]);
for (uint256 j = 0; j < bytesWord.length; j++) {
output[currentByte] = bytesWord[j];
currentByte++;
}
}
return string(output);
}
Is there a better way to do this?
Solution 1:[1]
You can simplify the function by using abi.encodePacked() that combines multiple values and returns a dynamic-length byte array (type bytes).
Since string in Solidity is effectively stored the same way as a byte array, you can then easily convert the output byte array to a string.
pragma solidity ^0.8;
contract MyContract {
function concat(string[] calldata words) external pure returns (string memory) {
bytes memory output;
for (uint256 i = 0; i < words.length; i++) {
output = abi.encodePacked(output, words[i]);
}
return string(output);
}
}
Try with ["hello", " ", "world"] for example.
Solution 2:[2]
I have just published an assembly implementation of javascript like Array.join() functions working for both reference types (bytes[] and string[]) and value types (bytes2[], uint16[], etc.). The lib is here and benchmarking it against a for loop with string.concat shows that it's up to 5x more efficient (depending on the number of strings and their length).
So using the above mentioned packages, it's like:
import {Array} from "@clemlaflemme.eth/contracts/lib/utils/Array.sol";
contract MyContract {
using Array for string[];
function foo(string[] memory arr) public pure returns (string memory) {
return arr.join();
// also return arr.join(","); for example
}
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Petr Hejda |
| Solution 2 | ClementWalter |
