Code challenge doesn't work

My solution for this challenge:
https://www.codecademy.com/code-challenges/code-challenge-find-the-missing-numbers-javascript

It is asking for:

You have a bag containing tiles with numbers [1, 2, 3, …, n] written on them. Each number appears exactly once, so there are n tiles and n numbers. Now, without looking, k number tiles are randomly picked out of the bag and discarded. Create a missingNos() function that takes in a list and k, and returns the missing numbers in ascending order (from smallest to greatest).

For example, missingNos([1, 2, 4, 5, 6, 7, 8, 10], 2) should return [3, 9].

I think my solution works for the above requirement but can’t pass codecademy’s built-in testings (shows only 1 out of 5 tests passed)
Please confirm that it’s not my fault,
or if it is, why? Thanks.

function missingNos(array, k) { const numArr = []; const indexArr = []; while (indexArr.length < k) { let indexToTake = Math.floor(Math.random()*array.length); let isRepeat = false; indexArr.forEach((index) => { if (indexToTake === index) { isRepeat = true; } }); if (!isRepeat) { indexArr.push(indexToTake); numArr.push(array[indexToTake]); } } numArr.forEach((num, index) => { for (let i = index + 1; i < numArr.length; i++) { if (numArr[index] > numArr[i]) { let val = numArr[i]; numArr[i] = numArr[index]; numArr[index] = val; } } }); return numArr; } const testArray = [1, 2, 4, 5, 6, 7, 8, 10]; console.log(missingNos(testArray, 2)); // Leave this so we can test your code: module.exports = missingNos;

Hi,
have you tested your code with different input arrays? I get rather random results then. And also the input array you used in your code returns different results each time it runs.

What is this line for: let indexToTake = Math.floor(Math.random()*array.length);
I cannot see how you get to the correct results with random numbers. You need to make sure that you go through each item in the array. The forEach method goes through an array chronologically by default which in this case makes the most sense.

I think you might have read that you’re supposed to remove the number tiles randomly, but you’re just checking to see which number tiles from 1 to n have been removed. Try tracking a count between 1 and n, checking if the current number is equal to the count, and doing something based on that check.

3 Likes

i think the above quote from the original question explicitly asked for random output

This quote explicitly asks for an ordered output:

Create a missingNos() function that takes in a list and k, and returns the missing numbers in ascending order (from smallest to greatest).

In other words, you are given the array of numbers with k numbers already randomly removed, and you’re being asked to make a function that says which numbers are missing.

1 Like

Thanks to your hints I corrected my logic and the output is not random now.

At first my logic was to pick k random non-repetitive numbers from the array and push to the result array and then sort them. (I misunderstood the question and thought the argument array was complete like [1,2,3,4,…,n]) But then I realized the argument array is already missing k numbers and I need to find them.

Here’re my steps after correcting my logic. It works more generally, when the array is unsorted and has missing numbers at both ends)
(e.g. array = [3, 7, 4, 10, 6]; k = 7)

  1. Create an empty array to be pushed to and returned
  2. Sort the argument array if it’s not already in ascending order (e.g. array = [3, 7, 4, 10, 6] => [3, 4, 6, 7, 10])
  3. Push missing small numbers starting from 1 (e.g. push 1, 2)
  4. Check if the sorted array has steps larger than 1 and push (e.g. push 5 then push 8, 9 )
  5. Check k to find out the biggest number and push missing big numbers (e.g. the largest number should be 12, so push 11, 12)
  6. Return (e.g. return [1, 2, 5, 8, 9, 11, 12]
function missingNos(array, k) { //declare array to be returned const missingNosArr = []; //define ascending order compare function const ascCompareFn = (a, b) => a - b; //sort the array if it's not ascending already array.sort(ascCompareFn); //get nos missing at the beginning for (let i = 1; i < array[0]; i++) { missingNosArr.push(i); } //get nos missing in the middle for (let i = 1; i < array.length; i++) { let diff = array[i] - array[i - 1]; if (diff !== 1) { for (let j = 1; j < diff; j++) { missingNosArr.push(array[i - 1] + j); } } } //get nos missing at the end const origLength = array.length + k; for (let i = array[array.length - 1] + 1; i <= origLength; i++) { missingNosArr.push(i); } //now ready to return return missingNosArr; } const testArray = [3, 7, 4, 10, 6]; console.log(missingNos(testArray, 7)); // Leave this so we can test your code: module.exports = missingNos;

Any further suggestions welcome!

According to the instructions, k stands for the amount of numbers missing in the array and therefore the amount of items in the array that you should return.

So for your input array

const testArray = [3, 7, 4, 10, 6];

k would be 3.
The array that should be returned in case of your testArray would be [5,8,9].

You don’t necessarily need to work with k. You can pass the tests even when you ignore k completely.

I have another unrelated javascript question for you:

I call a method on an object. And the method takes a callback function as a parameter. As:

obj.method(callbackFn);

Inside the callback function, I want to use the object the method is called upon. I want to define the callback function and save it to a global variable since I may use this callback later in multiple methods upon multiple objects. As:

const predeclaredCallbackFn = () => {};
anyObj.anyMethod(predeclaredCallbackFn);

So I have to use something like the this keyword to point to the object, instead of using its name. But I dont know how to.

For example, with the array.forEach method, say I want the callback to console log the array for each element of the array.
I will want to have something like this (not working):

const arr = [0, 1, 2]; //any 3 elements array

const callback = () => {
console.log(this);
}
//does using arrow function in this case make difference from using func declaration/expression?

arr.forEach(callback); // I want the callback to console log the array 3 times but not working. 
//it's logging ' {} {} {} ' to the console

Many thanks!

According to the question, the array at first was

You have a bag containing tiles with numbers [1, 2, 3, …, n]

In your reply:

[3, 7, 4, 10, 6];
k would be 3.
The array that should be returned in case of your testArray would be [5,8,9].

To my understanding, if the array has element 3, then at least 1 and 2 must also exist in the array OR they must be discarded before and included in the returned array.

Then the question says:

k number tiles are randomly picked out of the bag and discarded

What if the tiles left are [1,2,3] and 4,5,6,…,n were discarded? How do you know the value of k (has to depend on n in this case) from the array? To my understanding k must be given and cannot be determined by the argument array.

The test array in the code challenge provided by CC is

const testArray = [1, 2, 5, 6, 7, 8, 9, 10];

The function call in the challenge is

console.log(missingNos(testArray, 2));

k = 2
The array to be returned is

[3, 9]

From the instructions:

For example, missingNos([1, 2, 4, 5, 6, 7, 8, 10], 2) should return [3, 9] .

I just changed my testArray and function call to

const testArray = [5, 6, 7, 10];

console.log(missingNos(testArray, 2));

My code returns [ 8, 9 ]

It passes all tests.

You just need to add a parameter to your callback function:

const array = [1,2,3,4,5,6,7,8,9,10];

const logThis = (item) => {
    console.log(item);
}

array.forEach(logThis);

Sorry but i meant i wanted to work with the entire obj/arr in the callback func, not loopig through it.
In terms of the forEach example I would have wanted array.forEach(logThis) to:

for each of its 10 elements, console log the entire array once, logging 10 times in total

instead of just console log each of its 10 elements.
To accomplish this, I need to have a reference to the array inside the array.forEach(callback) function:

 array.forEach(
(element)  => {
console.log(the entire array, not the element)
} );

Or this example:

const callbackMale = () => {
  let name = this.name;
  return 'Mr. ' + name;
}

const callbackFemale = () => {
  let name = this.name;
  return 'Ms. ' + name;
}
//I need to use the 'name' property value of the object which a method using this callback is called upon
// i need this.name === object.name for the callback to work
};

const obj 1= {
  name: 'Foo'; 
  methodA(callback){
console.log(callback());
}
}

const obj2= {
  name: 'Bar'; 
  methodB(callback){
console.log(callback());
}
}

obj1.methodA(callBackMale); // Mr. Foo
obj2.methodB(callBackFemale); //Ms. Bar



(OR in general, let the callback do something to/with the obj/arr the method is called upon)

Ah, ok. Try something like this:

const array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

const obj = {
    a: [5, 7, 9],
    b: function() {
        console.log(this)
    }
}

obj.b.call(array)

Returns:

[
  1, 2, 3, 4,  5,
  6, 7, 8, 9, 10
]

But, to be honest, I just wouldn’t use forEach in that case. I’d just call logThis() or some similar function on the array itself instead of calling it from within a forEach, but it depends what you want to do.

Also, check this page out for clarifications on call, apply, and bind:

I will Try This for my project