freeCodeCamp Challenge Guide: Drop it

Drop it


Problem Explanation

Basically while the second argument is not true, you will have to remove the first element from the left of the array that was passed as the first argument.

Relevant Links


Hints

Hint 1

You can use Array.prototype.shift() or filter that you should be more familiar with to solve this problem in a few lines of code.

Hint 2

Shift returns the element that was removed which we don’t really need, all we need is the modified array that is left.

Hint 3

If you still can’t figure out how to solve it with shift, then try solving it with filter, and check how filter works, if you become familiar with it, then you can make the code with shift.


Solutions

Solution 1 (Click to Show/Hide)
function dropElements(arr, func) {
  while (arr.length > 0 && !func(arr[0])) {
    arr.shift();
  }
  return arr;
}

// test here
dropElements([1, 2, 3, 4], function(n) {
  return n >= 3;
});

Code Explanation

  • Use a while loop with Array.prototype.shift() to continue checking and dropping the first element of the array until the function returns true. It also makes sure the array is not empty first to avoid infinite loops.
  • Return the filtered array.

Relevant Links

Solution 2 (Click to Show/Hide)
function dropElements(arr, func) {
  let sliceIndex = arr.findIndex(func);
  return arr.slice(sliceIndex >= 0 ? sliceIndex : arr.length);
}

// test here
dropElements([1, 2, 3, 4], function(n) {
  return n >= 3;
});

Code Explanation

  • Use ES6 findIndex() function to find the index of the element that passes the condition
  • Slice the array from the found index until the end
  • There is one edge case! if the condition is not met against any of the elements ‘findIndex’ will return -1 which messes up the input to slice(). In this case use a simple conditional operator to return false instead of -1. And the ternary operator returns the found index of required elements when the condition is true, and the length of the array otherwise so that the return value is an empty array as is instructed.

Relevant Links

Solution 3 (Click to Show/Hide)
function dropElements(arr, func) {
  // drop them elements.
  let originalLen = arr.length;
  for (let i = 0; i < originalLen; i++) {
    if (func(arr[0])) {
      break;
    } else {
      arr.shift();
    }
  }
  return arr;
}

// test here
dropElements([1, 2, 3, 4], function(n) {
  return n >= 3;
});

Code Explanation

  • Create a for loop to check each element.
  • Then check for the function given if true then stop, otherwise remove that element.
  • return the array.

Relevant Links

Solution 4 (Click to Show/Hide)
function dropElements(arr, func) {
  return arr.length > 0 && !func(arr[0])
    ? (dropElements(arr.slice(1), func))
    : arr;
}

// test here
dropElements([1, 2, 3, 4], function(n) {
  return n >= 3;
});

Code Explanation

  • Use recursion to solve the challenge
70 Likes

Is this good procedure in the basic solution to declare a variable to store an object’s attribute, and then only use this variable once?

Wouldn’t it be clearer and simpler to write directly?

for (var i = 0; i < arr.length; i++)

9 Likes

Either way, I do use this for more longer variables.

It helps but in this case it can be done as you suggested.

1 Like

Actually, for (var i = 0; i < arr.length; i++) would not work. (How do I know? I just spent an hour trying to figure out why it wouldn’t work in my algorithm. :slight_smile: )

When you are using arr.shift(), this is shrinking the value of arr.length. Most of the time this is fine but for dropElements([1, 2, 3, 4], function(n) {return n > 5;}) you run out of loops before you go through the entire array.

28 Likes

That’s what I thought, but for some reason it will not return the correct solution unless you do that.

1 Like

Other solution:

function dropElements(arr, func) {
 	nope = []; yep = [];
 	for (i = 0; i < arr.length; i++){
 		if (func(arr[i]) === false && nope.includes(arr[i]) === false){
 			nope.push(arr[i]);
 		} else {
 			yep.push(arr[i]);
 		}
 	}
    return yep;
}

dropElements([1, 2, 3], function(n) {return n < 3; });
11 Likes

A recursive solution:

function dropElements(arr, func) {
  if (arr.length === 0 || func(arr[0])) {
    return arr;
  } else {
    arr.shift();
    return dropElements(arr, func);
  }
}
60 Likes

I like this a lot. I’m a total noob novice with recursive functions, but this one is really easy to understand. Thanks for posting.

12 Likes

@Rafase282 hi how you doing? I was trying to do this with filter but in filters how we can track each processing so that we can drop the element which is not satisfying the condition in the function.

Thanks in advance :slight_smile:

@sainiabhi @camperbot With filter:

/* jshint esversion: 6 */
dropElements=(arr, func, s = false) => arr.filter(a => {if (func(a)) s = true; return s;});

dropElements([1, 2, 3, 4], function(n) {return n >= 3;});
8 Likes

Just a small side note: I think this sentence is a bit misleading. Compared to using Array.prototype.shift() it is rather tricky to use the filter method for this task. Can someone revise the text or provide an easy solution using the filter method (I’d argue that the “esversion: 6” solution from Ibarjk is not that simple, in particular, if you are not familiar with arrow functions syntax)?

Hi there, I’m new and learning and my code is crude when I compare it. I just don’t know how to get to that next higher level of knowledge and understanding if you know what I mean? I am falling back on the same techniques again and again to try and solve these Bonfires and I haven’t found a course or site to learn more advanced/‘higher’ levels of JS. Does it really matter as long as a problem gets solved?

Anyway, my attempt at this challenge -

function dropElements(arr, func) {
// Drop them elements.
var check1 = arr.filter(func);

if (check1.length === 0){
return check1;
} else {

var check2 = arr.find(func);
return arr.slice(arr.indexOf(check2));
}
}

1 Like

function dropElements(arr, func) {
while (func(arr[0]) === false){
arr.shift();
}
return arr;
}

dropElements([1, 2, 3, 4], function(n) {return n >= 3;});

13 Likes

I think this has something to do with how .shift() operates within a for loop. If you jump into a console and do the following, the output is not what I thought I should expect:

for(var i=0; i< arr.length; i++){
  console.log(arr[i]);
  arr.shift();
}  //actual output: 1,3,2

Why? Because each iteration is dependent on arr.length’s current length.

//First iteration
i=0; // or 1 in arr
console.log(1);
arr.shift() //takes out 1
//Second
i=1 //or 3 because arr is now [2,3,4]
arr.shift() // takes out 3
//Third 
i=2 // breaks for loop because arr is now [2,4] there is no 2th index
arr.shift() // logs 2

Or at least I think that’s what’s happening.

8 Likes
function dropElements(arr, func) {
  // Drop them elements.
  var count = 0;
  while (!func(arr[count])) arr.shift();
  
  return arr;
}

dropElements([1, 2, 3], function(n) {return n < 3; });
5 Likes

How about this solution?

function dropElements(arr, func) {
  for (var i = 0; i < arr.length; i++)
    if (func(arr[i])) return arr.slice(i);

  return [];
}

I iterate over the Array to check if the test passes to an element then I simply slice the Array starting from that element until the last and return it back. If the test never passes, I simply return an empty Array.

13 Likes

Another solution.
> function dropElements(arr, func) {

  return arr.slice((arr.find(func)) ? arr.indexOf(arr.find(func)):arr.length);
}

Thanks! I’ve been beating my head against the wall on this one.