2

I'm transforming my array with Array.prototype.map(), and if the current item matches some conditions, I want to change its previous item.

The code below seems not working, how do I do it without a for loop?

var nums = [1, 2, 3, 4, 5];

var res = nums.map((item, index, array) => {
  if (item > 3) {
    array[index - 1] += 1;
  }
  return item;
});

console.log(res); // [ 1, 2, 3, 4, 5 ], I want [1, 2, 4, 5, 5]

0

5 Answers 5

2

You can use a reducer

var res = [1, 2, 3, 4, 5]
  .reduce((reduced, item, i) => {
     i && (reduced[i-1] += item > 3 ? 1 : 0);
     return [...reduced, item];
   }, []);

console.log(res); 

Sign up to request clarification or add additional context in comments.

2 Comments

double-click 666
years later, I've learned ... operator in reduce may cause perf issues, so I use push/splice in my recent project
1

Arrays that are in the process of being created from .map can't be referenced like that. Instead, create the array outside of the forEach, and push to / assign to it:

var nums = [1, 2, 3, 4, 5];
const newArr = [];
nums.forEach((item, index) => {
  if (item > 3) newArr[index - 1] += 1;
  newArr.push(item);
});

console.log(newArr); // I want [1, 2, 4, 5, 5]

1 Comment

I would like to add that .map() is what's called an out-of-place algorithm, which means that the output array is not the same reference as the input array.
1

Disclaimer: this answer is only here because I feel whenever somebody asks "how do I do X without a for loop", I feel there should at least be one recursive solution between all the maps and reduces :)

how do I do it without a for loop?

If you don't care much about performance or the risk of blowing the stack, you can go with a recursive function!

Here's an example:

  • Destructure your array into first, second and the rest
  • If first is empty, we've reached the end of our computation and return the result
  • If first is not empty, we can compare it to second to determine its value. We add the value to our result and recurse:
  • Call the function again, but now with [second, ...rest] and passing along our result

const input = [ 1, 2, 3, 4, 5 ];
const Empty = Symbol();

const incIfBt3 = 
  ([first = Empty, second, ...rest], result = []) =>
    first === Empty
      ? result
      : incIfBt3(
          [second, ...rest],
          [...result, first + (second > 3)]
        );
        
        
console.log(incIfBt3(input));

2 Comments

Disclaimer: Your idea is cool and interesting, but I think recursive code is harder to understand sometimes
Agreed! If you hadn’t already received so many good answers I wouldn’t have posted this one. I upvoted the answer by JLRishe because that’s the one I’d actually use in shared/production code 🙂
0

You can look ahead instead of trying to look behind:

var nums = [1, 2, 3, 4, 5];

var res = nums.map((item, index, array) => {
  if (array[index + 1] > 3) {
    item += 1;
  }
  return item;
});

Comments

0

Instead of trying to change the previous item, you can use the array parameter to look at the next item and return a value for the current item accordingly:

var nums = [1, 2, 3, 4, 5];

var res = nums.map((item, index, array) => item + (array[index + 1] > 3 ? 1 : 0));

console.log(res); // [1, 2, 4, 5, 5]

You can also take advantage of the fact that the numeric value of a boolean is either 1 or 0 to eliminate the conditional expression:

var nums = [1, 2, 3, 4, 5];

var res = nums.map((item, index, array) => item + (array[index + 1] > 3));

console.log(res); // [1, 2, 4, 5, 5]

1 Comment

There's a mass downvoter on the loose! Show yourself!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.