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.
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.
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)
Create an empty array to be pushed to and returned
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])
Push missing small numbers starting from 1 (e.g. push 1, 2)
Check if the sorted array has steps larger than 1 and push (e.g. push 5 then push 8, 9 )
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)
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;
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:
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
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.
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)
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: