Passed into the function array is undefined - javascript

I want to enhance merge sort algorithm so that it sorts two arrays and removes duplicates.
I've came up with the following code:
function mergeSortEnhanced(arr, arr2)
{
while(arr2.length)
{
arr.push(arr2.shift());
}
if (arr.length < 2)
return arr;
var middle = parseInt(arr.length / 2);
var left = arr.slice(0, middle);
var right = arr.slice(middle, arr.length);
return merge(mergeSortEnhanced(left), mergeSortEnhanced(right));
}
function merge(left, right)
{
var result = [];
while (left.length && right.length) {
if (left[0] < right[0])
{
result.push(left.shift());
}
else if(left[0] > right[0])
{
result.push(right.shift());
}
else
{
result.push(left.shift());
right.shift()
}
}
while (left.length)
result.push(left.shift());
while (right.length)
result.push(right.shift());
return result;
}
var a = [1, 2 , 2 , 1];
var b = [1, 1, 6 ,8];
console.log(mergeSortEnhanced(a, b).join());
The problem is that i encounter an error in the fourth line
while(arr2.length)
which states that compiler cannot compute length of undefined. i don't understand why the second array is undefined inside the function and how do I fix it

The problem is with the
return merge(mergeSortEnhanced(left), mergeSortEnhanced(right));
you pass only first parameter in function here, thus second one is undefined.
maybe you wanted to do
return merge(left, right);
BTW just as an advice - be extremely careful with recursion

Add check before while. Update your code as
if (arr2){
while(arr2.length)
{
arr.push(arr2.shift());
}
}
The shift() method removes the first item of an array, and returns that item. So after 4 iterations your arr2 becomes undefined.

Related

How could value be added to an array when there haven't any yet?

This comes from a problem in freeCodeCamp JS course: 'Use Recursion to Create a Countdown'. The code goes like this:
function countup(n) {
if (n < 1) {
return [];
} else {
const countArray = countup(n - 1);
countArray.push(n);
return countArray;
}
}
console.log(countup(5));
When countArray is created, it isn't an array, it just equal to countup (n-1). So how could the value n be pushed into countArray?
The base case of the recursion creates the array with
return [];
This is returned to the previous case, which pushes into it and returns the array again with return countArray;

isSorted function in Javascript: How to use for-of-loop in the code

I am a beginner in JS writing code, and I have a question about the isSorted function.
I am supposed to use for-of-loop in the code.
Here is the task:
Declare a function isSorted.
/**
* #param {Array<number>} ??? - an array of numbers
* #returns {boolean} whether or not the given array is sorted
*/
Here is what i wrote
function isSorted(array) {
const result = [];
for (const number of array) {
if (number < number1 && number2 ) {
result.push(number);
}
return true;
}
}
Here is the error message that I get
Here is the test that I could not pass with my code above
actual = isSorted([1, 2, 3]);
expected = true;
if (actual === expected) {
console.log("Test PASSED.");
} else {
console.error("Test FAILED. Keep trying!");
console.group("Result:");
console.log(" actual:", actual);
console.log("expected:", expected);
console.groupEnd();
}
actual = isSorted([3, 2, 3]);
expected = false;
if (actual === expected) {
console.log("Test PASSED.");
} else {
console.error("Test FAILED. Keep trying!");
console.group("Result:");
console.log(" actual:", actual);
console.log("expected:", expected);
console.groupEnd();
}
Try this isSorted function:
function isSorted(array) {
let previousNo = null;
for (const number of array) {
if (previousNo != null && number < previousNo) {
return false;
}
previousNo = number;
}
return true;
}
It still uses the for..of loop, and here's what it's doing:
"previousNo" will store the number that had been looked at during the previous iteration of the loop, so we can see if our current number is less than it. if it is, that means that the numbers are not stored in ascending order, i.e., it isn't sorted (so we return false in this case).
If no problems were found in the loop, we return true instead (your version did this as well, the only difference is, you returned true inside the loop, preventing the other items from being checked).
You can compare the i-th element of the array with the next one. If one element is greater than the following the array is not sorted
function isSorted(array) {
for (let i = 0; i < array.length; ++i) {
if (array[i + 1]) {
if (array[i] > array[i + 1]) {
return false;
}
}
}
return true;
}
Or you can reduce your array to a boolean value (see Array.prototype.reduce()):
function isSorted(array) {
return array.reduce((prev, cur) => prev !== false && cur >= prev && cur)
}
where prev is the the value resulting from the previous iteration and cur the current iteration item.
This fuction compare array members: first with second, second with third...etc. If the following member of the array is less than the actual, return false(array is not sorted).
function isSorted(array) {
for (var i = 0; i<array.length; i++) {
if (array[i] > array[i+1]) {
return false;
}
}
return true;
}

An element of an array doesn't pass a test

I am writing a function that loops through an array and tests each element for a condition. If it is false, the element is dropped. If it is true, the function returns the rest of the array.
Here is my code:
function dropElements(arr, func) {
// Loop through the array
for(var i = 0; i < arr.length; i++){
// if the current element passes the test, return the rest of the array
if (func(arr[i])){
return arr;
// otherwise remove the element
} else {
arr.shift();
}
}
// if no conditions were met, return empty array
return arr;
}
When the loop reaches i = 1, we have arr[1] = 2.
Since 2 is not >= 3, I do not understand why it is not dropped.
So, why does the following call
dropElements([1,2,3,4], function(n) {return n >= 3; });
return [2,3,4] instead of [3,4] ?
Thanks.
Because when you "shift" it removes the index and the other indexes shift down to fill in the hole. So when you remove the first one, the second index is now one. And since you increment i, you skip the index that was moved down.
So to get around your issue, you would need to reduce i
else {
arr.shift();
i--;
}
Or you can do another solution where you find the index and than just splice the array.
From MDN doc:
The shift() method removes the first element from an array and returns that element. This method changes the length of the array.
In your code this means that you have to sync the index in the loop. You can simply decrease the index by 1
function dropElements(arr, func) {
// Loop through the array
for(var i = 0; i < arr.length; i++){
// if the current element passes the test, return the rest of the array
if (func(arr[i])){
return arr;
// otherwise remove the element
} else {
arr.shift();i--;
}
}
// if no conditions were met, return empty array
return arr;}
This will solve your problem
It has to do with the order in which you are shifting the array. Take into comparison the following:
function dropElements(arr, func) {
if (!Array.isArray(arr) && arr.length == 0) {
return [];
}
while (!func(arr[0]) && arr.length > 0) {
arr.shift();
}
return arr;
}
epascarello's answer should be accepted as the correct one, however here is an updated code block for what you need:
function dropElements(arr, func) {
// Loop through the array
for(var i = 0; i < arr.length; i++){
// if the current element passes the test, remove it from the array
if (func(arr[i])){
return arr;
} else {
arr.shift();
i--;
}
}
// Return the array
return arr;
}
var arr = [1,2,3,4,2];
dropElements(arr, function(num) {
return num >= 3;
});
This outputs [3, 4, 2] (this is because we assume that the array is ordered when we loop through it and return from the function when the test function is satisfied once). If you want to loop on an unordered array, simply remove the return arr in the loop, just note that this will run at O(n) opposed to O(log n)

JavaScript Remove Multiple Values from Array Using Filter and Loop

I'm new here and need some help with writing a function destroyer() to remove multiple values from an array.
The destroyer() function passes in an array and additional numbers as arguments. The idea is to remove the numbers from the array.
E.g.
destroyer([1, 2, 3, 1, 2, 3], 2, 3)
Output: [1, 1]
destroyer(["tree", "hamburger", 53], "tree", 53)
Output: ["hamburger"]
destroyer([2, 3, 2, 3], 2, 3)
Output: []
Note: the examples only show 2 additional numbers to remove. But the function destroyer() should be able to remove any number of values (i.e. 4, 5, or 6 parameters).
However, my code does not produce the same result. Specifically, using console.log, I see that my filterer function does not loop properly.
1) Can anyone help me debug?
2) Any better way to write this function?
Thank you very much!!!
function destroyer() {
var args = Array.prototype.slice.call(arguments);
var itemToRemove = args.slice(1);
console.log(itemToRemove);
var newArr = args[0];
console.log(newArr);
function filterer(value) {
for (var i = 0; i < itemToRemove.length; i++) {
console.log(i);
console.log(itemToRemove[i]);
if (value != itemToRemove[i]) {
return value;
}
}
}
return newArr.filter(filterer);
}
Your filterer function can be much simpler:
function filterer (value) {
return itemToRemove.indexOf(value) === -1;
}
Using Array.prototype.indexOf() can be inefficient compared to object property lookup in terms of time complexity. I would recommend looping through the additional arguments once and constructing an object with target elements to be destroyed as keys. Then you can check if a given value is a target or not within a filtering callback that you pass to Array.prototype.filter().
function destroyer() {
var arr = arguments.length && arguments[0] || [];
var targets = {};
for (var i = 1; i < arguments.length; i++) {
targets[arguments[i]] = true;
}
return arr.filter(function (x) {
return targets[x] === undefined;
});
}
One downside to this approach is that not all values in JS can be valid properties of an object, since properties must be strings. In this case, you're just using numbers as keys, and those numbers are implicitly converted to strings.
We can pass the arguments an extra parameter to our callback function in our filter() method.
function destroyer(arr) {
return arr.filter(filterer(arguments)); // Pass arguments
}
function filterer(args) {
return function(value) { // Actual filter function
for (var i = 1; i < args.length; i++) {
if (value === args[i]) // Seek
return false; // Destroy
}
return true; // Otherwise keep
};
}
This passes all 5 test cases for freeCodeCamp | Basic Algorithm Scripting | Seek and Destroy.
The following code will remove elements from an array. The elements it removes are defined by any extra parameters. ...remove is an ES6 feature that aggregates extra parameters into a single array.
I will iterate over the ...remove array and delete that element from the main array we are working on.
Here is a JSFiddle: https://jsfiddle.net/zzyopnnp/
...extra_parameters is not supported in most browsers, you may want to use the arguments object.
function removeIndex(array, index) {if(index>-1){array.splice(index, 1);}}
function destroyer(array, ...remove) {
remove.forEach(function(elem, index) {
removeIndex(array, index);
});
};
var arr = ["tree", "hamburger", 53];
destroyer(arr, "tree", 53);
console.log(arr);
A simple function
function filter(arr, arg1, arg2){
var j = arr.length;
while(j){
if (arr.indexOf(arg1) > -1 || arr.indexOf(arg2) > -1){
arr.splice(j - 1, 1);
}
j--
}
}
For multiple arguments
A simple function
function filter(){
var j = -1;
for(var i = 1; i < arguments.length; i++){
j = arguments[0].indexOf(arguments[i]);
if(j > -1){
arguments[0].splice(j, 1);
}
}
return arguments[0];
}
you can call this function with no of args
eg:
filter([1,2,3,4,5,6,7,8,9], 1, 3, 5); //return [2,4,6,7,8,9]
filter([1,2,3,4,5,6,7,8,9], 1); //return [2,3,4,5,6,7,8,9]
There are really good answers here, but you can do it very clean in this way, remember you have an objects option in filter method which you can use in the callback function, in this case i'm using it like : arguments[i] so I can check every value in the arguments array
function destroyer(arr) {
for(var i = 1; i < arguments.length; i++){
arr = arr.filter(isIn, arguments[i]);
}
function isIn(element,index, array){
if (element != this){
return element;
}
}
return arr;
}

Recursive Array Reversal Javascript

So we are practicing functional javascript in my programming class with this assignment and I just can't get it to work right. Any advice in making this code work would be appreciated. Everything but the body was given for me to use. Here is what I have come up with:
(It is always sending me just the first array index content rather than all of them reversed. I tried changing it to
if(arr.length <= 1) return arr;
but that never hits the base case.)
function ReverseArray(arr) {
//base case
if(arr.length == 1)
{
return arr[0];
}
if(arr.length == 0)
{
return 0;
}
var head = arr.pop;
var newArr = [head, ReverseArray(arr)];
return newArr;
}
x = y <--assignment
z == y <-- comparison
Looking at your code:
if(arr.length = 1)
needs to be
if(arr.length == 1)
same with the zero check
AND you are not calling pop
var head = arr.pop;
you need to parenthesis
var head = arr.pop();
This is the most precise and clean way to do it in a single line with the ternary operator.
function reverse(arr) {
return arr.length < 2 ? arr : [arr.pop()].concat(reverse(arr));
}
console.log(reverse([4, 3, 3, 1]));
Here's a runnable example with a working function. FYI there is also a built-in function that will do this for you.
I think other than the confusion with assignment/comparison operators, when you were building the result array, you should be using Array.concat() to concatenate your array, instead you were building a new array where the second item was an array itself.
var a = [1,2,3,4,5];
console.log(ReverseArray(a));
function ReverseArray(arr) {
if(arr.length < 2) {
return arr;
} else {
return [arr.pop()].concat(ReverseArray(arr));
}
}

Categories

Resources