Reputation: 15
I've an array: var old_array = [1, 2, 3, 4, 5]
If 5
exists in this array, remove it otherwise add it.
var new_array = [];
var number_existed = false;
for(var i=0,len=old_array.length;i<len;i++) {
if(old_array[i] == 5) {
new_array = old_array.slice(i+1);
number_existed = true;
break;
} else {
new_array.push( old_array[i] );
}
}
if(!number_existed) {
new_array.push(5);
}
It works, but I need improvements. How can I improve this code. I wanna see reduce
function in action but just not able to come up with anything logical.
Upvotes: 1
Views: 70
Reputation: 1667
If you really want to use reduce()
:
function togglePresenceOfFive(array) {
if (array.length === 0) { // Reduce can't handle this case because the loop never runs
return [5];
} else {
const reduceResult = array.reduce((acc, next, index, arr) => {
const isLast = index === arr.length - 1;
if (next === 5) {
return {
newArray: acc.newArray,
fiveFound: true
};
} else if (!acc.fiveFound && isLast) {
return {
newArray: acc.newArray.concat(next, 5),
fiveFound: false
}
} else {
return {
newArray: acc.newArray.concat(next),
fiveFound: acc.fiveFound
};
}
},
{ newArray: [], fiveFound: false }
);
return reduceResult.newArray;
}
}
return reduceResult.newArray;
}
But this is more readable in my opinion (assuming you don't mind mutating the original array):
function togglePresenceOfFive(array) {
const indexOfFive = array.indexOf(5);
if (indexOfFive > -1) {
array.splice(indexOfFive, 1);
} else {
array.push(5);
}
return array;
}
Upvotes: 0
Reputation: 50807
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 tofilter
. 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.
Upvotes: 1
Reputation: 291
Using reduce
is not best approach, because reduce is used to return a single item. In my solution I use findIndex and apply your logic.
function usingFunctions(old) {
var index = old.findIndex( function(it) { return it == 5 } );
var new_arr = old.slice( index + 1 );
if( index < 0 ) new_arr.push(5);
return new_arr
}
var old = [1, 2, 6, 8, 5, 3, 6, 9];
console.log( usingFunctions(old) );
old = [1, 2, 6, 8, 3, 6, 9];
console.log( usingFunctions(old) );
Upvotes: 1
Reputation: 36351
You can find it using indexOf
to get the index, and remove it using splice
or add it using push
var array1 = [1, 2, 3, 4, 5]
function modify_array(value, array) {
let idx = array.indexOf(value)
idx > -1 ? array.splice(idx, 1) : array.push(value)
return array
}
// Test cases
// Remove 5
console.log(modify_array(5, array1))
// Add 10
console.log(modify_array(10, array1))
Upvotes: 0
Reputation: 14927
You can check if the element already exists with Array.includes
, then either Array.filter
it to remove it, or append it using spread syntax:
function addOrRemove5(arr) {
return arr.includes(5) ? arr.filter(v => v !== 5) : [...arr, 5];
}
console.log(addOrRemove5([1, 2, 3, 4, 5]));
console.log(addOrRemove5([1, 2, 3, 4]));
Upvotes: 3
Reputation: 138567
let fiveFound = false;
const result = input.filter(it => it !== 5 || !(fiveFound = true));
if(!fiveFound) result.push(5);
reduce
won't help you here.
Upvotes: 1
Reputation: 36594
You don't need reduce()
just use filter()
var old_array = [1, 2, 3, 4, 5]
var new_array = old_array.filter(x => x === 5);
console.log(new_array);
Upvotes: 0