0

Trying to make a function that removes every number from an array (in place) except those between the last two parameters in the function. Those should be left. I got this exercise from:

https://javascript.info/array-methods

So why does this not work?

/*
 * Array excercize Filter range in place.
 * remove all except between a and b
 */
"strict"

var arr = [5, 3, 8, 1, 0, 11, 13, 100, 72, 80, 30, 22];



function filterRangeInPlace(arr, a, b) {
  arr.forEach(function(item, index, array) {
    if ((item < a) || (item > b)) {
      array.splice(index, 1);
    }
  });
}

filterRangeInPlace(arr, 11, 30);
console.log(arr);
Heretic Monkey
  • 11,687
  • 7
  • 53
  • 122
brat
  • 586
  • 5
  • 17
  • Use a reverse `for` loop (from last index to 0) so that `splice` doesn't affect future indexes. – Heretic Monkey Oct 13 '20 at 20:14
  • The `forEach` doesn't respect when you've deleted an element from the array. That means when you delete one item from the array at `index`, the next item at `index + 1` becomes the element at `index`, and then the `forEach` goes to `index + 1`, skipping that item. – Abion47 Oct 13 '20 at 20:15
  • Does this answer your question? [How to remove element from array in forEach loop?](https://stackoverflow.com/questions/24812930/how-to-remove-element-from-array-in-foreach-loop) – Heretic Monkey Oct 13 '20 at 20:17

3 Answers3

1

The forEach function doesn't respect when you've deleted an element from the array. That means when you delete one item from the array at index, the next item in the array at index + 1 becomes the element at index, and then the forEach moves on to the item at index + 1, skipping the item that is now at index.

You can correct this behavior by using a while loop instead.

var arr = [5, 3, 8, 1, 0, 11, 13, 100, 72, 80, 30, 22];

function filterRangeInPlace(arr, a, b) {
    arr.forEach(function(_, index, array) {
        var item = array[index];
        while((item < a) || (item > b)) {
            array.splice(index, 1);
            if (index >= array.length) break;
            item = array[index];
        }
    });
}

filterRangeInPlace(arr, 11, 30);
console.log(arr);
Abion47
  • 22,211
  • 4
  • 65
  • 88
  • Unsurprisingly, this is a common enough blunder that there are plenty of duplicates to choose from... – Heretic Monkey Oct 13 '20 at 20:20
  • I read that post. Must admit I just saw that code was similar, then something about doing it in reverse. So I miss took it for another kind of problem. I understand now why this happened. I also miss took it as an easy enough exercise where surprises would be next to impossible. Sorry guys, you rock I suck. Just get frustrated sometimes because I feel I'm struggling in the "kids pool" forever, instead of swimming in the deep end already :-/ – brat Oct 13 '20 at 20:35
  • @brat Well, the general thing that post is trying to say is that `forEach` isn't a great function in general when working on an array *that you are actively adding and removing items to.* In-place edits of an array can lead to these kinds of hiccups, and are also the source of other data-based errors in general. Instead, use the reverse method that post describes or use the `filter` function (which has simpler syntax anyway) for returning an entirely new array to avoid the in-place issues altogether. – Abion47 Oct 13 '20 at 20:38
  • Had to do it "in place" though, to adhere to the rules. Hopefully I wont forget this blunder for a while. – brat Oct 13 '20 at 20:44
0

On your code, when using splice on array variable, it also applies on arr value too. So if you remove one element on array, it also removes one from arr because array is reference of arr.

Instead of using forEach, you can simply do it using Array.filter.

/*
 * Array excercize Filter range in place.
 * remove all except between a and b
 */
"strict"

var arr = [5, 3, 8, 1, 0, 11, 13, 100, 72, 80, 30, 22];



function filterRangeInPlace(arr, a, b) {
  return arr.filter((item) => item >= a && item <= b);
}

console.log(filterRangeInPlace(arr, 11, 30));
Derek Wang
  • 10,098
  • 4
  • 18
  • 39
  • The whole point of the exercise was using `splice` to do the filtering on the array *in-place*. `filter` doesn't edit the array in-place, but instead returns an entirely new array. (Which is usually preferable behavior so as to not accidentally mutate the original array, but again, that wasn't the purpose of the exercise.) – Abion47 Oct 13 '20 at 20:18
-1

/*
 * Array exercise Filter range in place.
 * remove all except between a and b
 */
"strict"

var arr = [5, 3, 8, 1, 0, 11, 13, 100, 72, 80, 30, 22];



function filterRangeInPlace(arr, a, b) {
  return arr.filter(function(item) {
    if ((item < a) || (item > b)) {
      return item;
    }
  });
}

arr = filterRangeInPlace(arr, 11, 30);
console.log(arr);
bendelszl
  • 62
  • 4