Max Koretskyi
Max Koretskyi

Reputation: 105497

What is the most performant way to concatenate a string with a separator

Suppose I need to implement a simple join function that takes an array and returns a concatenated string of elements separated by a separator. Kind of what built-in method Array.prototype.join does. All implementations I've seen result in one redundant separator at the beginning or at the end and hence there is a need to trim the string.

For example, I can do it like this:

let s = "";
for (let i=0; i < arr.length; i++) s += sep + arr[i];
// redundant separator at the beginning, need to remove it
s = s.substr(1);

Or like this:

let s = "";
for (let i=0; i < arr.length; i++) s += arr[i] + sep;
// redundant separator at the end, need to remove it
s = s.slice(0, -1);

Is there a better approach that doesn't produce redundant separator? Import that implementation should efficiently handle all cases like empty array etc.

One way I can think of is to put an if statement inside the loop that checks if it's the first/last element and doesn't add a separator in that case, but that seems to be inefficient. Any ideas?

Upvotes: 2

Views: 146

Answers (5)

גלעד ברקן
גלעד ברקן

Reputation: 23955

Using reduce:

function join(arr, sep){
  if (!arr.length)
    return '';

  return arr.reduce((a,b) => a + sep + b);
}

console.log(join([1,2],'^'));

Upvotes: 1

Max Koretskyi
Max Koretskyi

Reputation: 105497

Another possible option is using recursion:

function join(a, separator) {
    if (a.length === 0) return '';

    function concat(a, n) {
        return n > 0 ? concat(a, n - 1) + separator + a[n] : a[n];
    }
    return concat(a, a.length - 1);
}

One limitation is that it can't handle large strings of tens of thousands character because of call stack size restrictions.

Upvotes: 0

Salketer
Salketer

Reputation: 15711

let s = arr[0] || "";
for (let i=1; i < arr.length; i++) s += sep + arr[i];

Add the first element, start looping at the second, adding the separator in front.

As you point out in your question, you could use a condition to only append the separator when needed, removing the need to get rid of the redundant one. The problem is, it might be correct if you are joining two or three values, but having to test in every loop iteration will get costly with big arrays.

Upvotes: 2

Nina Scholz
Nina Scholz

Reputation: 386604

For the first element, you could check for the length of the array and take the stringed value or an empty string.

Then loop as Salketer in his answer is doing:

let s = arr.length && arr[0].toString() || '';
for (let i=1; i < arr.length; i++) s += sep + arr[i];

Upvotes: 2

Suren Srapyan
Suren Srapyan

Reputation: 68655

If you want to define it yourself you can iterate till to the length- 1. After the loop you can add the last item only without separator.

Example

let arr = [1,2,3,4,5];
let sep = '-';

function customJoin(array, separator) {

   if(array.length === 0) {
      return '';
   }

   let s = '';
   let length = array.length;

   for (let i = 0; i < length - 1; i++) {
      s += arr[i] + separator;
   }

   return s + arr[length - 1];
}

console.log(customJoin(arr, sep));

Upvotes: 1

Related Questions