Im trying to get a sum of array injected into a function that loops until all the values are added, the console.log right before the "return" logs the right value, meaning the code works, but when I try to use that function with any array it returns "undefined"...
var total = function(arr) {
console.log(arr);
if(arr.length > 1) {
var temp = []
for(var i=0, len=arr.length-1; i<len; i++) {
temp.push(arr[i] + arr[i+1]);
}
total(temp);
}
else {
console.log(arr.join()); // 48, exectly what I need
return parseInt(arr.join());
}
}
var sup = total([1,2,3,4,5]); // undefined
Not completely sure how to debug it..
If your arr.length is greater than one, you will invoke total with the temporary array, however, you don't do anything with this temporary array - you don't return it, or utilize it in any way, so the intermediate results are lost.
In addition - this is not a self invoking function; it is recursion.
Related
I have this simple function "decode" that takes in 2 arrays as input, where the second array is used to decode the first array.
The starting input (not when the function recurses) must always be of the following format:
1st array is of length 1
2nd array is of a length that is a power of
2, minus 1 (1,3,7,15,...)
Example input:
([4],[0,2,6])
For some reason, my code always returns undefined when I try to return a decoded array. In fact, I can't seem to return anything other than undefined, even when I change the return statement to something like "return false". The log statements show that the correct values are being captured for both arrays, leaving me very confused.
Here's my code:
var decode = function(A, B){
console.log("A: "+A+" B:"+B);
console.log(B.length);
if(B.length===0){
return A;
}
var newA = [];
var newB = [];
var act = 0;
for(let i=0; i<A.length; i++){
newA[act] = A[i] - (B[i]/2);
newA[act+1] = A[i] + (B[i]/2);
act+=2;
newB = B.slice(i+1);
}
decode(newA, newB);
}
console.log("Answer is" + decode([4], [0,2,6]));
This will always return undefined, regardless of what you make the return statement. Console.log(A); on the other hand is giving me the correct value for what I want to return.
Thank you very much for the help! Greatly appreciated.
The problem is that if B.length != 0, there is no return value.
Change
decode(newA, newB);
to
return decode(newA, newB);
Normally I don't have too much trouble figuring out a problem in JS but this time I really need some help understanding this block of code. Mary Rose Cook used this logic in her space invaders game to filter through the bodies array to find collisions with other bodies.
var bodies = [];
...
update: function () {
// bodies is an array of all bodies in the game
var bodies = this.bodies;
var notCollidingWithAnything = function (b1) {
return bodies.filter(function(b2) { return colliding(b1, b2); }).length === 0;
};
this.bodies = this.bodies.filter(notCollidingWithAnything)
// ...insert function to draw the bodies that are in the new bodies array...
}
Can someone please explain how this.bodies.filter(notCollidingWIthAnything) works without passing in any parameters to the argument function? How does the the compiler know to check each element of the array against each other element of the array? Please guide me through what exactly happens in the compiler so that I can understand this.
Can someone please explain how this.bodies.filter(notCollidingWIthAnything) works without passing in any parameters to the argument function? How does the the compiler know to check each element of the array against each other element of the array?
The compiler (well, the JavaScript engine) doesn't know how to call notCollidingWIthAnything with the elements; Array#filter does.
notCollidingWIthAnything is a reference to the function. (Functions are proper objects in JavaScript, so we have references to them just like we have references to other objects.) The code passes that reference into Array#filter, and then Array#filter calls that function once for each element in the array, passing in the element value (and index, and array; it passes three args although we usually only use the first). Then it uses the return value of the callback to decide whether to include the element in the new array it builds.
Here's simplified code for Array#filter so you can see what's going on:
function arrayFilter(callback) {
// Remember this is called with `this` referring to an array-like object
// Create a new, empty array for the result
var result = [];
// Loop through the items
for (var index = 0; index < this.length; ++index) {
// Get the value for this entry
var value = this[index];
// Call the callback
if (callback(value, index, this)) {
// Got a truthy return value, include the value in the result
result.push(value);
}
}
// Return the new array
return result;
}
Again, that's simplified, not perfectly correct; for the perfectly correct steps, see the algorithm in the spec.
Here's an example with logging showing exactly who's doing what:
function arrayFilter(callback) {
console.log("Starting arrayFilter");
var result = [];
for (var index = 0; index < this.length; ++index) {
var value = this[index];
console.log("arrayFilter calling callback with value " + value);
if (callback(value, index, this)) {
console.log("arrayFilter got truthy result, include the value");
result.push(value);
} else {
console.log("arrayFilter got falsy result, don't include the value");
}
}
console.log("arrayFilter done");
return result;
}
function isOdd(value) {
var retval = value % 2 == 1;
console.log("isOdd called with " + value + ", returning " + retval);
return retval;
}
var a = [1, 2, 3, 4, 5, 6, 7, 8, 9];
console.log("calling `arrayFilter` with `a` as `this`, using `isOdd` callback");
var odds = arrayFilter.call(a, isOdd);
console.log("Resulting array: ", odds);
hi a would like to ask why this code returns a function and not the x value.
Thanks in advance.
function f() {
function makeClosure(x) {
return function(){
return x;
};
}
var a = [];
var i;
for(i = 0; i < 3; i++) {
a[i] = makeClosure(i);
}
return a;
}
var a = f();
console.log(a[0]);
makeClosure is returning functions, so your array a is filled with functions.
a[0] will return the function, a[0]() will return x
If you look at makeClosure you will see that it returns a function that in turns returns x.
Within the loop a[i] = makeClosure(i); assigns the function returned by makeClosure(i) in the array at the i index.
Running a function at a specific index in the array will return the related x value.
a[0](); should return 0.
Function f() returns an array.
So var a=f() assigns an array in a.
Now each array element is itself a function. So if you access any array element in the array a it will simply access the function definition but will not execute it.
Hence to execute the function you need to call the array elements as a function i.e. in place of a[0] in console.log(a[0]); you need to use console.log(a[0]());
This was the only reason...
I am wondering, what is the best approach to write a recursive function with no direct base case (say: factorial), for instance, to count the number of elements in a nested array I have two approaches in mind, the first one below is preferred as it returns result directly:
the second one keeps the count in a variable attached to the function, works fine, but dealing with the result & resetting the variable is bizarre.
any pointers are appreciated.
You can simply return the value you are interested in:
function countElements(arr) {
var count = 0;
for (var i=0; i<arr.length; i++) {
if (arr[i] instanceof Array) {
count += countElements(arr[i]); // recursion here
} else {
count++; // normal element counts as 1
}
}
return count;
}
Demo: http://jsbin.com/ejEmOwEQ/1/edit
WARNING: The function might not end if the array contains self reference (var arr = []; arr.push(arr); countElements(arr);)
The correct way to write this is simply:
function countElements (obj) {
if (obj instanceof Array) {
var count = 0;
for (var i in obj)
count += countElements(obj[i]);
return count;
}
return 1
}
The terminating condition you're looking for is if not instanceof Array. Which in my code above is simply the fall through from the if instanceof Array block.
You do not need to keep a temp variable like count in recursive functions. You're still thinking iteratively (well, that for loop is iterative so you need a count variable there).
Recursive functions do everything by accepting arguments and returning results. No assignments are necessary. In fact, the code above can be written purely recursively without using a for loop and therefore without needing to use a count variable:
function countElements (obj) {
if (obj instanceof Array) {
if (obj.length) {
return countElements(obj.shift()) + countElements(obj);
}
return 0;
}
return 1;
}
There are 3 rules: if object is not an array we return 1, if object is an empty array we return 0 otherwise we count the first item in the array + the sum of the rest of the array.
Not sure why i keep getting undefined for this results any help would be great. The result is suppose to the the array with the x value at the beginning. thanks
var tester = [1,2,4];
Array.prototype.cons = function(x){
function reduce(results,y){
if(y == 1){
results.unshift(x);
return results;
}
else{
results.push(this[y-1]);
y = y-1;
reduce(results, y);
}
}
return reduce([], this.length);
}
document.getElementById('test').innerHTML = tester.cons(0)
You designed your reduce function to return results, but in your recusive call of it
else{
results.push(this[y-1]);
y = y-1;
reduce(results, y); // <--- HERE
}
You aren't doing anything with the returned value (such as returning it up the stack). This means that evaluation continues down your function, at the bottom of which there is no return statement. In JavaScript, no return statement means that the return value of the function call will be undefined
If you're just trying to move an element in the array to the front, you can simply use this instead of recursively going through the array.
var tester = [1,2,4];
Array.prototype.cons = function(x){
// Copy the array. This only works with simple vars, not objects
var newArray = this.slice(0);
// Check to make sure the element you want to move is in the array
if (x < this.length) {
// Remove it from the array
var element = newArray.splice(x, 1);
// Add to the beginning of the array
newArray.unshift(element);
}
return newArray;
}
document.getElementById('test').innerHTML = tester.cons(4);
EDIT: Made a copy of the array