One more solution, expanding on my comment:
Jeto's answer should solve this. There is no real reason to use reduce for this, as it would just complicate things. If you were just filtering out the existing 5s, reduce
would be an overcomplicated but not unreasonable alternative to filter
. But since you also want to add a 5 if it's not there, your accumulator is going to need to carry extra state -- or you would store it somewhere worse. Such code is feasible, but quite ugly compared to the alternatives.
Here is what such uglier code might look like:
const addOrRemove5 = (arr) => {
const {found, xs} = arr.reduce(
({found, xs}, x) => x === 5 ? {found: true, xs} : {found, xs: [...xs, x]},
{found: false, xs: []}
)
return found ? xs : [...xs, 5]
}
console.log(addOrRemove5([1, 5, 2, 3, 4, 5])) //=> [1, 2, 3, 4]
console.log(addOrRemove5([1, 2, 3, 4])) //=> [1, 2, 3, 4, 5]
This uses an accumulator that looks like {found: boolean, xs: [number]}
, starting with {found: false, xs: []}
, updating found
to be true
on each 5
, and adding each non-5 to the values. Then after that runs, we return either the existing values or the existing values and an additional 5
, depending on the value of found
.
Again, this is much uglier than Jeto's solution. I would not recommend it here. But such techniques are not terribly uncommon when you need carry additional information as well as reducing a value. And a variant of this could let you work only with expressions and not any statements, by putting the resulting {found, xs}
object in a default parameter:
const addOrRemove5 = (
arr,
{found, xs} = arr.reduce(
({found, xs}, x) => x === 5 ? {found: true, xs} : {found, xs: [...xs, x]},
{found: false, xs: []}
)
) => found ? xs : [...xs, 5]
Again this is not recommended in this case, but it's a useful trick to know.