0

I have this code here, which should take in the length of these different items, and if the length is greater than 4, it should remove those values. However, it says the if (array[i].length>4) is undefined

let words = ["Apple", "Ben", "Ice", "Dog", "Tornado"];

function removeWords(array) {
  for (var i = 0; i < array.length; i++) {
    console.log(array[i].length);
  }
  if (array.length > 4) {
    array[i].splice();
  }
}

console.log(removeWords(words));
Chris G
  • 7,957
  • 4
  • 17
  • 29
Arsene
  • 25
  • 5
  • 2
    Take a look at [Array.prototype.filter](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter) – Anthony Jul 14 '20 at 16:06
  • The error occurs because the for loop will finally increment `i` to 5, then exit because the condition is no longer true. Next you're trying to access `array[5]`, which is undefined. You also forgot the `[i]` when testing the length, you're doing it *outside* the for loop, and even if you fixed all that, you'd still remove elements from an array while iterating over it, which is not well defined and will give bad results. – Chris G Jul 14 '20 at 16:10
  • Not a perfect dupe, but here's a "one size fits all" question: [How can I remove a specific item from an array?](https://stackoverflow.com/questions/5767325/how-can-i-remove-a-specific-item-from-an-array) – Chris G Jul 14 '20 at 16:12

2 Answers2

3

You can use Array.filter()

let words = ["Apple", "Ben", "Ice", "Dog", "Tornado"].filter(w => w.length <= 4);


console.log(words);
Harun Yilmaz
  • 6,857
  • 3
  • 21
  • 31
2

There are a number of things wrong with this code, I'm afraid. The simple answer has already been supplied: use filter. If that's all you want to know, great. If you want to work through this to get a working version, here are some steps:

We start with

let words = ["Apple", "Ben", "Ice", "Dog", "Tornado"];

function removeWords(array) {
  for (var i = 0; i < array.length; i++) {
    console.log(array[i].length);
  }
  if (array.length > 4) {
    array[i].splice();
  }
}

console.log(removeWords(words));

The very first thing to notice is that we call console.log on the result of calling removeWords. But removeWords doesn't return anything. So let's fix that first:

function removeWords(array) {
  for (var i = 0; i < array.length; i++) {
    console.log(array[i].length);
  }
  if (array.length > 4) {
    array[i].splice();
  }
  return array;  // <--------------------- added  
}

But now let's look at the test you're doing. if (array.length > 4). You want to be testing inside your loop, as you want to test every word in the list. You already have the loop, but it only contains the debugging code of a console.log statement. Let's move that out and move the test and its related change inside it:

function removeWords(array) {
  for (var i = 0; i < array.length; i++) {
    if (array.length > 4) {  //  ---\
      array[i].splice();     //  --- >---- moved inside loop
    }                        //  ---/
  }
  return array;
}

But now let's look at that actual test. We should be checking that the word has a length greater than 4, not that the array does. So we need to check if array[i] > 4:

function removeWords(array) {
  for (var i = 0; i < array.length; i++) {
    if (array[i].length > 4) {  // <------ changed
      array[i].splice();
    }
  }
  return array;
}

We have the opposite problem in the splice call. You are trying to call splice on the word, when you want to do it on the array. You want to remove one element at the ith index in the array. We can fix that with

function removeWords(array) {
  for (var i = 0; i < array.length; i++) {
    if (array[i].length > 4) {
      array.splice(i, 1);  // <----------- changed
    }
  }
  return array;
}

The next problem is more subtle. And it won't even affect your test case. But if we run this function against this list: ["Apple", "Ben", "Ice", "Dog", "Tornado", "Windshield", "Axe"], we will get back ["Ben", "Ice", "Dog", "Windshield", "Axe"]. We include "Windshield" here because of the interaction between your loop and the splice call. We proceed merrily along until i is set to 3. At this point our array includes ["Ben", "Ice", "Dog", "Tornado", "Windshield", "Axe"] because we've already removed "Apple". We check index 3, see that "Tornado" has more than four letters, and splice again, leaving ["Ben", "Ice", "Dog", "Windshield", "Axe"]. But now the index is 4, and our test word is "Axe" We've skipped over "Windshield"!

This happens because, while you want to test every word in the array, your splice call is changing the length of the array as you go. One way to fix this is to loop in reverse. By starting from the end, the splice will affect the indices only of things you have already tested. That might look like this:

function removeWords(array) {
            //      +--------------+-----+- changed
            //      |              |     |
            //      v              v     v
  for (var i = array.length - 1; i >= 0; i--) {
    if (array[i].length > 4) {
      array.splice(i, 1); 
    }
  }
  return array;
}

This is the first working version of the code. We could leave it there. But there is still a potential issue. You're changing the input as you go. There is a strong school of thought that finds this to be a pretty terrible thing to do. So instead of changing our original input data, let's make a copy of it first, then change and return this. There are many ways we could make a shallow clone of the input, including using slice or concat. The modern one is probably to use the spread notation like this:

function removeWords(words) {
            //         ^--------+---------- changed
  let array = [...words] // <---'
  for (var i = array.length - 1; i >= 0; i--) {
    if (array[i].length > 4) {
      array.splice(i, 1); 
    }
  }
  return array;
}

This is now a reasonable version of the function ... if we didn't already have Array.prototype.filter available. You can see it in action in the following snippet:

function removeWords(words) {
  let array = [...words]
  for (var i = array.length - 1; i >= 0; i--) {
    if (array[i].length > 4) {
      array.splice(i, 1); 
    }
  }
  return array;
}

let words = ["Apple", "Ben", "Ice", "Dog", "Tornado"];
let words2 = ["Apple", "Ben", "Ice", "Dog", "Tornado", "Windshield", "Axe"];

console.log (removeWords(words));
console.log (removeWords(words2));

console.log ("--------------\nOriginals Untouched\n--------------")

console.log (words);
console.log (words2);
.as-console-wrapper {min-height: 100% !important; top: 0}
Scott Sauyet
  • 37,179
  • 4
  • 36
  • 82
  • 1
    If I had another upvote! This is more than just an answer, this is a complete step-by-step tutorial. SO is such a great source thanks to people like you. – Harun Yilmaz Jul 14 '20 at 20:22