Where does this function gets its values? - javascript

This is an example from a book. The function returns TRUE if even and FALSE if not. I don't understand how it works. This is what I understand:
42 binds to n
Creating "even" function
x binds to n which = 42
x != 0
initiating "else"
creating "odd" function
odd(42 - 1)
Initiating "!even(41)".
What does JS do with "even(41)"? where TRUE comes from? The way I understand it should return TRUE only when x === 0
document.write(
((n) => {
const even = (x) => {
if (x === 0) return true;
else {
const odd = (y) => !even(y);
return odd(x - 1);
}
}
return even(n)
})(42)
)

It's intentionally confusing. Follow the logic.
If n is not 0, we create a new function called odd which calls even and reverses the boolean value of even.
We then call that function with n-1.
So essentially, it's like a while loop where you keep subtracting 1 from the number and reversing its truthiness or falsiness on each step deeper, until you have a 0. If the function is called an even number of times, it's even. If it's called an odd number of times, it's odd.

The following code performs the same logic as the book example, including use of recursion, but prevents an infinite loop if isEven is called with a non integral or negative value.
const isEven = (n) =>
{
const even = (x) => x ? !even(x-1) : true;
return even( Math.abs(Math.floor(n)));
}
isEven( 42)
Now the bench logic test is fairly straight forward:
even( 0) returns true;
even( 1) returns !even( 1-1), which is !even(0), which is false;
even( 2) returns !even( 2-1), which is !even(1), which is true;
and so on for higher numbers. Each increment of the parameter value executes an additional, recursive call to even, which complements the "even-ness" of the number below it, until reaching zero which is hard coded as being even.
The end result is that if even is called an odd number of times (for an even number) isEven returns true; and if even is called an an even number of times (for an odd number) isEven returns false.

Related

Can someone explain canSum to me please

The question states:
Write a function canSum(targetSum, numbers) that takes in a targetSum and an array of numbers as arguments. The function should return a boolean indicating whether or not it is possible to generate the targetSum using numbers from the array. You may use an element of an array as many times as needed. You may assume that all numbers are nonnegative.
In the dynamic programming video I am watching the solution is:
const canSum = (targetSum, numbers) => {
if (targetSum === 0) return true;
if (targetSum < 0) return false;
for (let num of numbers) {
const remainder = targetSum - num;
if (canSum(remainder, numbers) === true) {
return true;
}
}
return false;
}
I understand how this code works with many scenarios like canSum(7, [2, 3]). However I don't understand this piece: if (targetSum === 0) return true; that means canSum(0, [2, 3]) will result in true. That's not how this code should work according to the question. What am I missing here?
Thank you
console.log(canSum(7, [2, 4]))
resulted in false
however
console.log(canSum(0, [2]))
resulted in true
When it says you can use any numbers as many times as you want, that includes using all of them zero times, and when you do this the sum is 0. Using this as the base case of the recursion simplifies the algorithm, since you just keep subtracting until you get to 0.
An alternative way would be to use numbers.includes(targetSum) as the base case. They're equivalent because when this is true, one of the iterations of the for loop will set remainder to 0, and the recursive call will have targetSum === 0.

Does indexOf != -1 return a Boolean?

I have just started learning Javascript and I have a specific question about a specific piece of code below. It is part of the lycanthrope's log in chapter 4 of Eloquent Javascript. Because of the specificity of my question I haven't included all the other code associated with this problem for I believe it isn't necessary to answer my question.
Please do let me know if this is considered 'bad practice' and I will make sure to ammend this and/or future posts to show more background.
In the code below the second line shows a return. So far I have learned that indexOf returns a positive number or zero if and only if it finds an occurence of whatever is passed in it. If no occurence is found it returns -1.
In this case it is followed by != -1, which I understand to mean "not equal to minus 1". That is clear to me.
What I do not completely understand is what the actual return in line 2 ends up being. Does it return a Boolean value of either true or false? Or does it return he actual index where the 'event' is found?
Further on, in the first if-statement, we see the hasEvent variable again. I read this statement as "If hasEvent(event, entry) is true then add 1 to the index.
Am I 'reading' this right and is the return in the second line indeed a Boolean?
function hasEvent (event, entry) {
return entry.events.indexOf(event) != -1;
}
function tableFor (event, journal) {
var table = [0, 0, 0, 0];
for (var i=0; i < journal.length; i++) {
var entry = journal[i] , index = 0;
if (hasEvent(event, entry)) index += 1;
if (entry.squirrel) index += 2;
table [index] += 1;
}
return table;
}
Thank you for your help and please tell me if I should have stated this question differently! I am trying to make sure I understand things before I move on!
The != operator always has a boolean result.
A return statement followed by an expression returns the value of the expression, so the returned value of that function will be either true or false.
Yep. Using ===, ==, !, !==, !=, >, >=, < or <= results in a boolean expression, which would return a boolean from hasEvent.
Comparison operators all evaluate to a boolean value.
More to the point, what this code is specifically doing is abstracting a comparison behind a function name. Any operation or set of operations which results in a value can be placed in a function which returns that value. Doing so is a common refactoring to make code more readable and understandable, as the name of the function can impart intuitive meaning on the operation being performed.
So instead of something like this:
if (a == b) {
}
you can have this:
if (someCondition(a, b)) {
}
So you can give a meaningful name to the operation (more meaningful than someCondition of course). As long as that function returns the same value as the code it replaces, logically there is no difference.
Explanation
By default, the indexOf function returns the index location of the substring.
A bitwise shortcut can be used with indexOf as well as other functions:
~ (bitwise not operator):
This works similar to ~x => -(x+1)
Simply checking against this value (for example using an if statement) yields true for non-zero values and false for zero.
If you need the actual boolean value instead, you can use the following: !!~. Here, the double exclamation !! is non-inverted boolean representation. Combining both essentially flips the result of indexOf, then converts it to boolean representation.
A better explanation of ~ can be found here. A better explanation of !! can be found here
Example
let s = 'abc'
/*
console.log(~s.indexOf('a')) // -1
console.log(~s.indexOf('b')) // -2
console.log(~s.indexOf('d')) // 0
console.log(!~s.indexOf('a')) // false
console.log(!~s.indexOf('b')) // false
console.log(!~s.indexOf('d')) // true
console.log(!!s.indexOf('a')) // false
console.log(!!s.indexOf('b')) // true
console.log(!!s.indexOf('d')) // true
console.log(~~s.indexOf('a')) // 0
console.log(~~s.indexOf('b')) // 1
console.log(~~s.indexOf('d')) // -1
*/
// This one works
console.log(!!~s.indexOf('a')) // true: 0 => -1 => false => true
console.log(!!~s.indexOf('b')) // true: 1 => -2 => false => true
console.log(!!~s.indexOf('d')) // false: -1 => 0 => true => false

Range using recursion, how to output a new array Javascript

How do you output a new array using recursion without declaring an empty array outside of the function? Another way of doing it will be creating an inner function and then return newFunction(), but it is not allowed as the task is to call the function itself. Here's what I have so far:
var newArr=[];
var range = function(x, y) {
if(x === y-1){
return newArr;
}
if(x < y){
newArr.push(x+1);
newArr = range(x+1,y);
}
else{
newArr.push(x-1);
newArr = range(x-1,y);
}
return newArr;
};
range(2,10) //[3,4,5,6,7,8,9]
So the key to this kind of thinking is understanding that you should be creating a lot of arrays.
Looking at a slightly different example...
A factorial is a number which goes backwards, through positive integers, multiplying each term with the term below it, and is written like 5!.
These are helpful when you find yourself asking questions like:
"How many permutations of ____ are there?"
"Given these 5 things, how many permutations can I arrange them in, from left to right?"
5! // =>
5 x 4 x 3 x 2 x 1 // =>
120
You could see how we could build a loop and set a variable for a counter, and a variable for the total, and multiply the current total by the current value of the counter we're decrementing.
But instead of doing that, we can try to use recursion.
First, think about how we could simplify that 5 x 4 x ... into one repeated step.
Really, 2! is 2 x 1. 3! is 3 x 2 x 1, which happens to be 3 x 2!.
So the general case might be something like: n! == n x (n - 1)!
So I might write a generalized function which does something like this:
// DO NOT RUN THIS FUNCTION!
function factorial (n) {
return n * factorial(n - 1);
}
So if I run factorial(5) and use my imagination, we can see that the program is doing something like:
factorial(5)
=> return 5 * factorial(5-1)
=> return 4 * factorial(4-1)
=> return 3 * factorial(3-1)
=> ...
Can you see any problems with the function as-is?
I said at the beginning that factorials (in this simplified case) are over positive integers.
How does my function know to stop when the integers stop being positive?
It doesn't, currently. Which is why the above implementation attempts to run forever, and will freeze the browser, while it tries to, until it gets thousands or tens of thousands of functions deep, before it says that you've reached the maximum depth of the call stack and explodes.
What we really need is a condition or a set of conditions, which we use to determine when we're done.
This is a base-case.
if (shouldStop(n)) {
return defaultValue;
}
Or in our case:
function factorial (n) {
if (n <= 1) {
return 1;
}
return n * factorial(n - 1);
}
Now, when we run the function, we have:
factorial(5)
=> 5 * factorial(5 - 1)
=> 4 * factorial(4 - 1)
=> 3 * factorial(3 - 1)
=> 2 * factorial(2 - 1)
=> 1
=> 2 * 1
=> 3 * 2
=> 4 * 6
=> 5 * 24
=> 120
This is recursion.
And because of where the call is (returned at the very end of whatever branch you're in) it's a special kind of recursion (tail recursion), which allows some languages to optimize the code, replacing the function call with the contents of the function call, and thus skip adding to the call-stack like the first version (future versions of JS will support this power).
In more modern JS, I might rewrite it to look something like
const factorial = n => n <= 1 ? 1 : factorial(n - 1);
So now, what about other cases?
Well, sometimes, you need to make sure you're passing more things in.
Think about what your problem is, and what kinds of counters or flags or collectors you need, in order to do your job.
Here's one:
function makeNumberString (current, max, initialString) {
var str = initialString || ""; // maybe I don't have one yet
var currentString = str.concat(current.toString());
if (current > max) {
return initialString;
}
return makeNumberString(current + 1, max, currentString);
}
makeNumberString(0, 9); // "0123456789"
There are other ways of filling that function out, to make it do the same thing.
Note that currentString there is always a brand new string, made by joining the string that I was given with the new value I was passed. I'm not actually modifying the original string, but creating a new copy [HINT!!].
I hope that helps you.
you can simply do like this;
var range = (x,y,a=[]) => (++x < y && (a = range(x,y,a.concat(x))),a),
arr = range(2,10);
console.log(arr);
Note that the returned array is a parameter of the function and is passed to successive recursive calls.
There are many ways to skin this cat.
The simple way: create an array with the first value in it, then
concatenate the remaining values to it.
var range = function(x,y){
return x+1 >= y ? [] : [x+1].concat(range(x+1, y));
}
console.log(JSON.stringify(range(1, 10)));
The array is being constructed from right to left. Notice how the
recursive call to range is not the last thing the function does
before it returns: concatenation of the array follows.
We can also rewrite the function to be tail recursive with an accumulator as a parameter.
var range2 = function(x,y,a){
a = a || [];
return x+1 >= y ? a : range2(x+1, y, a.concat(x+1));
}
console.log(JSON.stringify(range2(1, 10)));
Now the call to range2 is the last thing the function does before
it returns. ES6 compliant JS engines are required to
optimise
calls in tail position (in strict mode) by discarding the execution
context from the stack.
Notice how we're now constructing the array from left to right.
You can avoid the extra parameter by using a helper function.
I've used an inner function, but it doesn't have to be.
var range3 = function(x,y){
var r = function(x,y,a){
return x+1 >= y ? a : r(x+1, y, a.concat(x+1));
}
return r(x, y, []);
}
console.log(JSON.stringify(range3(1, 10)));
Tail recursive using continuation passing style.
var range4 = function(x,y){
var r = function(x,y,c){
return x+1 >= y ? c([]) : r(x+1, y, function(a){
return c([x+1].concat(a));
});
}
return r(x, y, function(a){return a;});
}
console.log(JSON.stringify(range4(1, 10)));
Notice the similarity with the original range: the array is
constructed in reverse. This is trickier to get your head around and
may be something you never need, but it doesn't hurt to be aware of
it.
Try this:
function rangeRecursive(start, end) {
if(start === end){
return end;
} else if(start > end){
return [];
} else {
return [start].concat(rangeRecursive(++start, end));
}
}
console.log(rangeRecursive(4, 15));

Returning true in recursive function when atleast 1 condition is met

Aspiring programmer here, whilst doing some challenges on coderbyte I came across a little problem that I can't seem to solve. The challenge is as follows;
Find the largest value in an array and check if any combinations of the other ints (excluding the largest number) amounts to that largest number. Return true if a combination has been found, false otherwise.
I got the all the parts of the question down, except the returning part. Which you'd think it's the easiest part.. Not for me though. Here's the code:
function ArrayAdditionI(arr, largest, partial) {
var n, sumPart, remaining, largestI, result;
// declace the next partial array, or start with an empty one
partial = partial || [];
// find the largest value from the original array,
// use the existing one if already declared
largest = largest || arr.reduce(function(max, cur) {
if(cur>max) return cur;
else return max;
});
// sum up possible combinations of the partial array
sumPart = partial.reduce(function (a, b) {return a + b;}, 0);
// sumPart equal to largest int? return true
if(sumPart === largest) {
console.log("%s=%s", partial.join("+"), largest);
return true;
}
// sumPart more than desired number? Stop
if(sumPart > largest) {
console.log("%s>%s", partial.join("+"), largest)
return;
}
for(var i=0;i<arr.length;i++) {
n = arr[i];
if(n != largest) {
remaining = arr.slice(i + 1);
ArrayAdditionI(remaining, largest, partial.concat([n]));
};
};
return false;
};
// keep this function call here
// to see how to enter arguments in JavaScript scroll down
ArrayAdditionI([4,6,23,10,1,3]);
It logs the correct answer(s) according to the first -if statement-, however, it never logs the "true" no matter what I seem to do. On the one hand I can see this returning false everytime since it's at the end of the function. On the other hand shouldn't this return true as soon as it meets true? Had this problem before, time to find out how to actually see this, and thereby fix it...

How do you compare whether or not two functions behave the same in Javascript?

If I have 2 functions as vars, f1 and f2 - how can I determine whether or not the 2 functions will behave the same for all inputs? That is, they will return the same value for all inputs.
It is not going to be possible for arbitrary functions.
For example, consider the Collatz function (n becomes 3n+1 if n is odd or n/2 if n is even). It is hypothesised that all positive integers eventually end up in the cycle 4->2->1. Suppose that your functions are designed to indicate the cycle that the input reaches (or indicate if it never reaches a cycle). f1 might just print 4->2->1 but f2 might repeatedly apply the function until a cycle is detected (and have some other case for determining if it is not in a cycle). There are no currently known inputs where f1 and f2 give different answers but it is unknown whether such an input exists.
No, you cannot. The number of possible inputs to the given functions is infinite. So unless you know about some relation between them, a finite number of values will guarantee nothing.
One way is to write function which compares the outputs of some other functions which have been given the same input argument(s). Possible Input arguments can be pushed into an array to ease the process. Something like...
var func1 = function(inputValue) {
// return some stuff
};
var func2 = function(inputValue) {
// return some stuff
};
var inputArray = [/* some input values */];
function compare(array) {
var isSame = false;
for (var i = 0; i < array.length; i++) {
if (func1(array[i]) === func2(array[i]) {
isSame = true
} else {
return i
}
}
return isSame
}
var result = compare(inputArray);
if (typeof result === 'number') {
alert('Comparison failed at inputArray['+result+'] : ' + inputArray[result])
} else {
alert('Comparison success!')
}
The compare() fucntion returns two different types of result depending on the the if-condition. If all if-conditions are met we get a boolean (true), otherwise the for-loop stops and returns the index number where the comparison failed - which can then be used to point back to the input value that broke the chain.

Categories

Resources