I am trying to implement the equivalent of .join() using .reduce() to answer a quiz on executeprogram.com. My code passes the tests, but it seems ugly. The specific issue that I have solved in an ugly way is this: The constructed join() function takes an array and a separator as arguments, but the separator should not be inserted after the last item of the array when constructing the resulting joined output. This means I have to test, when iterating over the array with reduce(), whether I am at the last item (so that I can skip using the separator) [oops: see note below]. Using indexOf or lastIndexOf doesn't work if there are duplicate values in the array. So I created a counter. I don't like it. I would love suggestions about how to do this better. Here's the code:
function join(arr, separator) {
let counter = 0;
if (arr.length === 0) { return(''); }
else {
return (
arr.reduce((accumulator, item) =>
{
if (counter === arr.length - 1) {
return accumulator + item;
} else {
counter += 1;
return accumulator + item + separator;
}
},
'')
);
}
}
The tests and their expected output are below. Again, the function above passes all the tests, but I think there has to be a better way.
> join(['a'], ',')
Expected: 'a'
> join(['a', 'b'], ',')
Expected: 'a,b'
> join(['a', 'b', 'c'], '')
Expected: 'abc'
> join(['a', 'b', 'c', 'd'], 'x')
Expected: 'axbxcxd'
> join(['a', 'b'], 'COMMA')
Expected: 'aCOMMAb'
> join(['', '', ''], ',')
Expected: ',,'
> join([], ',')
Expected: ''
NOTE: After seeing all the helpful answers, I realized that the real cause for this ugly code was my mistaken assumption that the separator comes "after" an item. Actually, the separator comes between items, and you can make it come between every item if you insert it before every item except the first one. Then you don't need to test for the last item. When you remove the assumption that you need to test for the last item, everything is much simpler. So basically, I stated the problem wrong in the first place. Thanks to everyone for the answers!