Higher-order function - javascript

I have an exercise about JavaScript. This exercise requires me to use higher-order functions. I have managed to specify some of the functions so far, but when I try to execute the code, the result does not seem to work properly. I have some images to give you an idea, hopefully, you can help me correct this.
The thread is: Write the function loop(loops, number, func), which runs the given function the given number of times. Also write the simple functions halve() and square().
This is my code:
function loop(loops, number, func) {
var loops = function(n) {
for (var i = 0; i < n; i++) {
if (i < 0) {
console.log('Programme ended')
}
if (i > 0) {
return n;
}
}
}
}
var halve = function(n) {
return n / 2
}
var square = function(n) {
return n ** 2;
}
console.log(halve(50));
console.log(loop(5, 200, halve));
console.log(loop(3, 5, square));
console.log(loop(-1, 99, halve));

Your current loop function declares an inner function and then exits. Ie, nothing actually happens -
function loop(loops,number,func){
// declare loops function
var loops= function(n){
// ...
}
// exit `loop` function
}
One such fix might be to run the supplied func a number of times in a for loop, like #code_monk suggest. Another option would be to use recursion -
function loop (count, input, func) {
if (count <= 0)
return input
else
return loop(count - 1, func(input), func)
}
function times10 (num) {
return num * 10
}
console.log(loop(3, 5, times10))
// 5000

so first things first: Higher-Order functions are functions that work on other functions.
The reason why you get undefined is because you are calling a function which doesn't return anything.
function x(parameter){
result = parameter + 1;
}
// -> returns undefined every time
console.log(x(5));
// -> undefined
function y(parameter){
return parameter+1;
}
// -> returns a value that can be used later, for example in console.log
console.log(y(5));
// -> 6
Second, you are using n for your for loop when you should probably use loops so it does the intended code as many times as "loops" indicates instead of the number you insert (i.e. 200, 5, 99).
By having the "console.log" inside a loop you may get a lot of undesired "programme ended" in your output so in my version I kept it out of the loop.
The other two answers given are pretty complete I believe but if you want to keep the for loop here goes:
function loop(loops, number, func){
if(loops>0){
for(let i = 0; i< loops; i++){ // let and const are the new ES6 bindings (instead of var)
number = func(number)
}
return number
}
else{
return "Programme ended"
}
}
function halve(n) { // maybe it's just me but using function declarations feels cleaner
return n / 2;
}
function square(n) {
return n ** 2;
}
console.log(halve(50));
console.log(loop(5, 200, halve));
console.log(loop(3, 5, square));
console.log(loop(-1, 99, halve));

Here's one way
const loop = (loops, n, fn) => {
for (let i=0; i<loops; i++) {
console.log( fn(n) );
}
};
const halve = (n) => {
return n / 2;
};
const square = (n) => {
return n ** 2;
};
loop(2,3,halve);
loop(4,5,square);

Related

Why is my function working when called by itself but not when I call it with another function? (Beginner javascript question)

I am working on some coding challenges (I am still a beginner). I was able to make both of these functions work, but when I try to call them together my second function just returns zero..
Both functions take in two parameters (or more). The first function counts the numbers between the two paramters and returns them in a string (1, 5) => [1,2,3,4,5] and the second sums them together (1,10) => 55. Any reason why these work individually but not together?
Thanks in advance!
`let range = (start, end) => {
numbers = [];
for(i = start; i<end+1; i++) {
if(i>=start){
numbers.push(i);
if (i>=end) {
console.log(numbers);
}
}
}
}
function sum(start, ...add){
let sumCounter = 0;
for(i = start; i<=add; i++) {
sumCounter += i;
}
return sumCounter;
}
console.log(sum(1,10)); //second function works
console.log(sum(range(1, 10))); //first function works, not second function `
There are a lot of things going on here. First make sure that you’re returning a value in the first function, and not just printing to the console. Second, when you say “if(i>=end)” that will always be true, so it isn’t needed. Also instead of saying “if(I>=end)” you can put “I==end” or just put the following code after the for loop. I would suggest that you return the numbers, and take that as a parameter for your sum function. I hope you’re able to follow all of that!
Here is a working option:
function range(start, end) {
var numbers = [];
for (i=start;i<end+1;i++) {
numbers.push(i)
}
return numbers;
}
console.log("Sum: " + range(5, 10).reduce((a,b) => a + b, 0));
Or this might be easier to understand:
function range(start, end) {
var numbers = [];
for (i=start;i<end+1;i++) {
numbers.push(i)
}
return numbers;
}
function sum(nums) {
var sum = 0;
for (i=0;i<nums.length;i++) {
sum += nums[i];
}
return sum;
}
console.log("Sum: " + sum(range(5, 10)));

Why are for...of and for loop behaving differently?

Just was performing simple task in JS which was to take integer as an input, divide it into single digits and multiply them ignoring all zeros in it.
I have solved it but had some troubles which were simply solved by changing the loop. I am just curious why the code did not work properly with the for loop and started to work as I it for for of loop. I could not find out the answer by my self. If somebody could tell where I am wrong.
First one works as intended, second one always returns 1.
function digitsMultip1(data) {
var stringg = data.toString().split("", data.lenght);
for (let elements of stringg) {
if (elements != 0) {
sum = parseInt(elements) * sum
} else {
continue
};
}
return sum;
}
console.log(digitsMultip1(12035))
function digitsMultip2(data) {
var sum = 1;
var stringg = data.toString().split("", data.lenght);
for (var i = 0; i > stringg.lenght; i++) {
if (stringg[i] != 0) {
sum = parseInt(stringg[i]) * sum
} else {
continue
};
}
return sum;
}
console.log(digitsMultip2(12035))
There is no big difference. for..of works in newer browsers
The for...of statement creates a loop iterating over iterable objects, including: built-in String, Array, Array-like objects (e.g., arguments or NodeList), TypedArray, Map, Set, and user-defined iterables. It invokes a custom iteration hook with statements to be executed for the value of each distinct property of the object.
Several typos
length spelled wrong
> (greater than) should be < (less than) in your for loop
Now they both work
function digitsMultip1(data) {
var sum=1, stringg = data.toString().split("");
for (let elements of stringg) {
if (elements != 0) {
sum *= parseInt(elements)
} else {
continue
};
}
return sum;
}
console.log(digitsMultip1(12035))
function digitsMultip2(data) {
var sum = 1, stringg = data.toString().split("");
for (var i = 0; i < stringg.length; i++) {
if (stringg[i] != 0) {
sum *= parseInt(stringg[i])
} else {
continue
};
}
return sum;
}
console.log(digitsMultip2(12035))
You might want to look at reduce
const reducer = (accumulator, currentValue) => {
currentValue = +currentValue || 1; return accumulator *= currentValue
}
console.log(String(12035).split("").reduce(reducer,1));

Add delay to recursive function without modifying it

Let's say function fib():
function fib(n) {
if (n < 2){
return n
}
return fib(n - 1) + fib (n - 2)
}
Now, let's say I want to display each step of this recursive function in a document.write, and progressively add the result of each iteration with a delay of 1000ms between steps. Can I do it without modifying the original function by perhaps having another function, passing this one as the argument, creating the output mechanism, and since it also returns a function, recursively add the delay?
No, but writing it as a generator instead would give you a useful interface to implement something like that
function*fib() {
for (let a = 1, b = 1, c = 0;; c = a+b, a = b, b = c) yield a;
}
const sleep = ms => new Promise(resolve => setTimeout(() => resolve(), ms));
const gen = fib();
// then, use it step by step
console.log(gen.next().value);
console.log(gen.next().value);
// OR with a delay inbetween
async function slowly() {
for (let v of gen) {
console.log(v);
await sleep(1000);
}
}
slowly();
Because your original function is synchronous, without modifying you cannot really call it as if it were asynchronous.
JavaScript allows you to overwrite a symbol like your function, fib. This allows you to redefine it whatever you just want. Maybe you could make it asynchronous with dynamically added behavior, I don't know, but that would be too complicated.
However, you said "I want to display each step of this recursive function ... with a delay of 1000 ms between steps". You can easily do this, because you can call fib synchronously, but print the results asynchronously! Example:
function fib(n) {
if (n < 2){
return n
}
return fib(n - 1) + fib (n - 2)
}
var queue = [];
var depth = 0;
var manageCall = function(fn){
return function() {
++depth;
let result = fn.apply(this, arguments);
--depth;
queue.push(" ".repeat(depth)+fn.name+"("+arguments[0]+") = "+result);
return result;
};
};
var fib = manageCall(fib);
fib(8);
var printDelayed = function() {
if (queue.length != 0) {
console.info(queue.pop());
setTimeout(printDelayed, 1000);
}
}
printDelayed();
fib is unchanged, but can follow how the recursion were executed.
Yeah, so ... You probably actually can do this, but you're gonna have to get really creative. This is extremely non-performant code, and likely would need some tweaks to actually function, but you could conceivably take this just a bit further to get what you're after.
What we're doing
So, we're going to be ripping out the guts of a defined function that's passed to our mangler function waitAndPrintFunc. That function will output the function as a string, and then use it to rebuild a Frankenstein function that's executed via eval.
PLEASE NOTE: Don't EVER use this in a production environment. This code is a living abomination just to prove that something like this could be done.
//global
let indexCounter = 0;
const waitAndPrintFunc = (func) => {
let wholeFunc = func.toString();
const funcName = wholeFunc.slice(8, wholeFunc.indexOf('(')).replace(' ', '');
let funcBody = wholeFunc.slice(wholeFunc.indexOf('{') + 1, wholeFunc.lastIndexOf('}'));
const returnIndex = funcBody.indexOf(`return ${funcName}`);
const meatyPart = funcBody.slice(returnIndex + 7);
wholeFunc = wholeFunc.split('');
funcBody = funcBody.split('');
funcBody.splice(
returnIndex,
funcBody.length - returnIndex,
`document.querySelector('.output').appendChild("step \${indexCounter++}: \${eval(meatyPart)}"); setTimeout(() => {${meatyPart}}, 1000);`
);
wholeFunc.splice(0, 9 + funcName.length, 'const MyRiggedFunction = ');
wholeFunc.splice(wholeFunc.indexOf(')') + 1, 0, ' => ');
wholeFunc.splice(wholeFunc.indexOf('{') + 1, wholeFunc.lastIndexOf('}'), ...funcBody);
console.log(wholeFunc.join(''))
eval(`${wholeFunc.join('')} ; MyRiggedFunction(1)`);
};
function fib(n) {
if (n < 2) {
return n;
}
return fib(n - 1) + fib(n - 2);
}
waitAndPrintFunc(fib);
I see that I can intercept a function call, if I intercept fib(n), it should be intercepted by its own recursive calls, right? https://bytes.babbel.com/en/articles/2014-09-09-javascript-function-call-interception.html I will try it
No, you can't do that.
You could definitely "tap" into fib in order to add some console.log:
// original function
function fib(n) {
if (n < 2){
return n
}
return fib(n - 1) + fib (n - 2)
}
// rebind the var `fib` to a wrapper to the original `fib`
var fib = ((orig) => (n) => {
console.log('tap:', n);
return orig(n)
}
)(fib);
console.log("result:", fib(7));
However if the prerequisite is that you cannot modify the original fib that means it's still working as synchronous function: adding the delay means that fib becomes asynchronous.
But the return value of fib itself, since it's recursive, is using an addition operator (fib(n - 1) + fib(n - 2)), and therefore is expecting an immediate value, not something delayed.
If the constraint is that you cannot modify the original fib but you can only tap into it, you can't add a timeout given the code you provided.
Said that, you can definitely tap into the function and schedule a console.log every 1000ms: however that means that the function is finished already to be executed, it's just the console.log for each step that is delayed.
And I don't think that's what you want.

Function that counts how often it call another function

I have a 'twice' function that return 2 of the argument passed into it. I also have another function 'runTwice' that counts the number of times it called the 'twice' function (the idea being that I want the 'twice' function to only run 'twice' no matter how often it is called via the 'runTwice' function). Can you please help?
Functions are given below:
var count = 1;
function twice(num){
return num*2;
}
function runTwice(func){
if (count<3){
count++;
return func;
} else {
return 'Function cannot run!';
}
}
var myFunc = runTwice(twice)
var output = [];
for (var i = 0; i < 3; i++){
output.push(myFunc(i));
}
console.log(output);
I would like the output to be [0, 2, 'Function cannot run!'].
I can make this work if I count the 'twice' function directly but I am looking to understand why this doesn't work as presented above.
Just for fun I'll make a generic expireAfter(invocable[, times[, message]]) function:
function expireAfter(invocable, times = 2, message = 'Function cannot run!') {
return function expires() {
if (times > 0) {
times--;
return invocable.apply(this, arguments);
}
return message;
}
}
function twice(n) {
return n * 2;
}
var myFunc = expireAfter(twice);
console.log(Array(3)
.fill()
.map((_, index) => myFunc(index))
);
The function runTwice should return another function that will decide whether to call the function func (using Function.prototype.apply) or to return a string message instead:
function twice(num){
return num * 2;
}
function runTwice(func){
var count = 0; // this will be trapped in a closure along with func
return function() { // this is the function that gets called
count++; // it increments its version of the count variable
if(count <= 2) // if count is less than 2
return func.apply(this, arguments); // then it calls the function func with whatever arguments passed into it and return the returned value of that call
return "Not available anymore!"; // otherwise (count > 2), then it returns a string
}
}
var myFunc = runTwice(twice);
for (var i = 0; i < 3; i++){
console.log(myFunc(i));
}
Even better:
You can pass in the number of times allowed as well:
function double(num) {
return num * 2;
}
function triple(num) {
return num * 3;
}
function run(func, times){
var count = 0; // this will be trapped in a closure along with func and times
return function() { // this is the function that gets called
count++; // it increments its version of the count variable
if(count <= times) // if count is less than times
return func.apply(this, arguments); // then it calls the function func with whatever arguments passed into it and return the returned value of that call
return "Not available anymore!"; // otherwise (count > times), then it returns a string
}
}
var double2times = run(double, 2); // double2times can only be called 2 times
var triple5times = run(triple, 5); // triple5times can only be called 5 times
for (var i = 0; i < 10; i++){
console.log("Double:", double2times(i));
console.log("Triple:", triple5times(i));
}

add a memoization to recursive algorithm

I have written a function for partitioning a number:
var combinations = function (i) {
var mem = [];
function inner(n, r, m) {
for (var k = m; k <= n; k++) {
if (k == n) {
r.push(k);
mem[r] = 1;
return mem;
}
else {
var copy = r.slice(0);
copy.push(k);
inner(n - k, copy, k);
}
}
}
return inner(i, [], 1);
}
In second step I would like to add a memoization to this algorithm, but can't think of implementing it the right way, beause there is no return statement until the very end (when return is specified e.g. in faactorial or fibbinacci I can add the memoization).
Can anybody drive me to the right direction?
[edit]
I need this algorithm to be as fast as possible. This is a competition for a kata at codewars: link
There is a requirement it must be executed under 6000ms for input up to 330.
That's the best algorithm I can think of, except how to store the partial results.
Here's a much simpler code that works:
function nr_partitions(n) { return p(n, n); }
function p(sum,largest) {
if (largest == 0) { return 0; }
if (sum == 0) { return 1; }
if (sum < 0) { return 0; }
return p(sum, largest-1) + p(sum-largest, largest);
}
It uses a well-known recurrence, p(n,k) = p(n,k-1) + p(n-k, k), where p(n.k) denotes the number of partitions of n where the largest part is at most k (e.g. p(3, 2)=2 because we only count 1+1+1,1+2, but not 3). For k=n we get the number of all partitions of n.
Adding memozation involves storing dictionary mapping pairs (sum, largest) to p(sum, largest).
I would go along the lines of:
var cache = {};
var combinations = function (i) {
if ( cache[i] ){
return cache[i];
};
var mem = [];
function inner(n, r, m) {
for (var k = m; k <= n; k++) {
if (k == n) {
r.push(k);
mem[r] = 1;
return mem;
}
else {
var copy = r.slice(0);
copy.push(k);
inner(n - k, copy, k);
}
}
}
cache[i] = inner(i, [], 1);
return cache[i];
}
But you'll have to modify your algorithm to make use of that cache (compute the biggest terms first ?)
Depending on your other requirements, you might want to consider using underscore.js which has its own _.memoize function.
The secret of memoization is that it exploits how closures work. When you define a function inside another scope, it has access to everything in that scope. When you return that function to somewhere outside the scope, it carries references to everything it can see inside the scope.
So to implement memorization, you need to make a function that returns another function, one that does the memorization check before calling the inner one.
Your code will look something like this:
/**
* Because we'll be returning "a function that returns a function" below,
* this needs to be executed immediately so combinations() is just
* a standalone function.
*/
var combinations = (function(i) {
/**
* mem needs to stay outside the scope of your inner function.
* If it's in a closure like this, JavaScript will keep its value
* around as long as combinations still exists.
*/
var mem = [];
/**
* A memoization wrapper should return a memoized function
*/
return function(i) {
/**
* Check if mem[i] is set and return it if it has been
*/
if(mem[i] !== undefined) {
console.log('returning memoized value');
return mem[i];
}
function inner(n, r, m) {
for (var k = m; k <= n; k++) {
if (k == n) {
r.push(k);
mem[r] = 1;
return mem;
}
else {
var copy = r.slice(0);
copy.push(k);
inner(n - k, copy, k);
}
}
}
/**
* If the value needs to be computed, we can set it at the same time
* as we return it instead of putting it in a temporary variable.
*/
console.log('computed');
return mem[i] = inner(i, [], 1);
}
}()); /** <--- That's the rest of the automatic execution */
console.log(combinations(5));
console.log(combinations(5));

Categories