How do I delete empty elements in Arrays? Why doesn't this work?

Example:

My aim is to return [1,3]


let arr = [1, , , 3];
for (let i = 0 ; i < arr.length ; i++) {
       if ( arr[i] === ' ' ) {
      arr.splice(i,1);
        }
     }
 return arr

This doesn’t work, but I don’t know why? Correct me if i’m wrong here but this code runs through each element in arr, tests if its an empty string (’ ') and splices that specific element if true.

Please keep your explanation along this same method of solving this problem. For example please don’t use filter() or any high functions as I dont understand those very well yet.

Thanks!

It isn’t an empty string, it’s undefined. Sort of. An empty string is a string, a hole is…nothing. Why have you got holes in the array in the first place though? They’re not a thing you ever want to have

1 Like

Going by the Chrome console it looks like testing for

undefined

will work.

There are indeed use-cases for sparse arrays. A javascript array is after all just a map from indices to values. If the mapping from raw data is inherently sparse then it is reasonable to start with

const heatMap = Array(10000000);

(for instance) which takes no memory (except a little overhead) than starting with an array filled with something like 10 million ‘undefined’ or zeroes which consumes lots of memory for no good purpose.

I’ve edited your post for readability. When you enter a code block into a forum post, please precede it with a separate line of three backticks and follow it with a separate line of three backticks to make easier to read.

See this post to find the backtick on your keyboard. The “preformatted text” tool in the editor (</>) will also add backticks around text.

Note: Backticks are not single quotes.

markdown_Forums

Thanks for the replies everyone!

DanCouper:

I didn’t know that actually, thank you. I’m working on the exercise ‘Basic Algorithm Scripting: Falsy Bouncer’. I’ve got holes in my array’s because I’m testing the arrays for the ‘Falsy’s’ ( false , null , 0 , "" , undefined , and NaN), splicing them out if found and returning the array without the ‘Falsy’s’. I’m finding that when I splice them the resulting array contains holes. My aim is to remove both the ‘Falsy’s’ and the resulting holes. This is what I’ve got so far but I still need to remove the resulting holes:

function bouncer(arr) {
   for (let i = 0;i < arr.length; i++) {
     if (arr[i] == true || arr[i] == false) {
      arr.splice(i,1);
      };
     
     if (Boolean(arr[i]) === false) {
      arr.splice(i,1); 
     };
     
   
   };
console.log(arr);
}

bouncer([false, null, 0, NaN, undefined, "",])

(Thank you ArielLeslie for pointing out how to post code!)

The above code returns the following array:

0, 

This is giving me strange results. First

console.log(Boolean(0));

returns:

false 

Therefore I would expect the above code to splice out the 0 in the array due to:

 if (Boolean(arr[i]) === false) {
      arr.splice(i,1); 
     };

but obviously it doesn’t!

Also, HarplingeTom I have since added an additional if-statement to weed out the holes as you have suggested:

 if (arr[i] === undefined) {
       arr.splice(i,1);
     };

However this doesn’t seem to want to remove the holes either. Still getting the same result.

Any suggestions?

I don’t understand a couple of things here.

Firstly, how are you getting an array with holes? splice removes and array element, it doesn’t leave the index. Only delete leaves holes (and shouldn’t be used with arrays), but you aren’t using that.

EDIT: ah I see why. It’s not because of splice, it’s because you’re deleting items from an array as you iterate over it. This won’t work:

So you have an array like [1,2,3,4]. You use a for loop, so you iterate for array.length. Say you start the loop, and splice out any numbers < 3. Item at index 0 is 1, 1 is less than 3 so splice out. Item at the next index, index 1, is 3, because 2 is now at index 0.

Make a new array and push to it.

Secondly, what this is here for:

if (arr[i] == true || arr[i] == false) {
  arr.splice(i, 1);
};

== uses type coercion to convert the values on the right and left side to a common type. Everything coerces to true or false. So that condition should be true for absolutely anything

1 Like

I guess main cause of your issues is you are manipulating the size of an array as you iterate over it. When you do this and remove elements, this will cause you to miss out values (and for the obverse, when you add elements, you end up with a loop that could never stop).

In your function create a new array. Iterate over the original array: push every value you want to keep to e new array. Then return it once you’ve finished.

2 Likes

DanCouper:

Wow that was real easy actually with the whole pushing what I want to a new empty array. I totally over thought what I was doing! Thanks!

I feel very confident with solving problems doing the push to new array method. Its an easy way to think of things for me.

Is this bad practice? Or is it generally ok to do this most of the time?

It is always easier to reason about the code if you don’t mutate the array you are working on. You are less likely to make errors, the code is simpler.

Is this bad practice? Or is it generally ok to do this most of the time?

Yea, do it all the time. There are specific times you want to mutate, but rule of thumb is don’t (until you know that it would be beneficial to do so), it will make your life easier. It will also make it much easier to grok things like filter, because they work basically exactly the same way

1 Like

You can just filter them out:

const arr = [1,,,4];
const newArr = arr.filter(el => el !== undefined); // newArr === [1,4]
1 Like

Please keep your explanation along this same method of solving this problem. For example please don’t use filter() or any high functions as I dont understand those very well yet.

2 Likes

I missed this one. Also, note that you are using strict equality and it’s not always the best choice. However, empty array indices are usually “null” or “undefined”. But the Array.Prototype.filter() method should be the best option for you… or you can iterate like you were trying to but use 'if (!true), because null and undefined are falsey… and but maybe i’m overthinking it.

Can you explain more about filter() function?

So if you’re trying to remove numbers greater than 10 from an array:

function tenOrLessOnly(inputArr) {
  const outputArr = [];
  for (let i =0; i < inputArr.length; i++) {
    if (inputArr[i] <= 10) {
      outputArr.push(inputArr[i]);
    }
  }
  return outputArr;
}

// Call it like
tenOrLessOnly([1,2,3,11,12])

But you can generalise that by passing in whatever the condition is as a function , so instead of saying “if the array element is less than or equal to ten, put that in the output”, you say “if this function returns true for the array element, put that in the output”:

function filter(inputArr, func) {
  const outputArr = [];
  for (let i =0; i < inputArr.length; i++) {
    if (func(inputArr[i])) {
      outputArr.push(inputArr[i]);
    }
  }
  return outputArr;
}

function tenOrLess(num) {
  return num <= 10;
}

// Call it like
filter([1,2,3,11,12], tenOrLess)
// Same as
filter([1,2,3,11,12], function(num) {
  return tenOrLess(num);
}
// Or
filter([1,2,3,11,12], (num) => tenOrLess(num));
// Or
filter([1,2,3,11,12], (num) => num <= 10);

But JS has a function for arrays that does this, filter, so instead of manually writing that loop, can just do:

function tenOrLess(num) {
  return num <= 10;
}

// Call it like
[1,2,3,11,12].filter(tenOrLess)
// Same as
[1,2,3,11,12].filter(function(num) {
  return num <= 10;
});
// Or
[1,2,3,11,12].filter((num) => num <= 10));

So for this challenge, you need to remove falsely values: to be explicit in the code, you can use JS’ Boolean() function which converts whatever you give it to be true/false (it doesn’t need this function, but the code if you leave it off can be a bit confusing if you don’t quite understand what JS is doing):

function. bouncer(arr) {
  return arr.filter(val => Boolean(val));
}

// Same as
function. bouncer(arr) {
  return arr.filter(Boolean);
}