How to ilterate with recursive function (javascript) - javascript

function numberSum(num) {
var str = num.toString();
var arrNum = str.split('').map(Number);//arrNum = [1, 2, 3];
//For-looping
var result = 0;
for (var i = 0; i < arrNum.length; i++) {
result = result + arrNum[i];
}
return result;
}
console.log(numberSum(22222)); // 2 + 2 + 2 + 2 + 2 = 10
I did this with For-looping and then iterate it. The question is, how do i did the same but with Recursive Function?

You could use only the first element for addition and call the function with the rest of the array again.
In this case, a check is made for the length, this returns either 0 if the array has no items or the item count, then a shift is made which returns the first item of the array. Additionaly the function is called again with the reduced array.
function iter(array) {
return array.length && array.shift() + iter(array);
// ^^^^^^^^^^^^ exit condition,
// if zero, return zero,
// otherwise return the
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^ iteration part
// return the first value and
// call recursion again
}
function numberSum(v) {
function iter(array) {
return array.length && array.shift() + iter(array);
}
return iter(v.toString().split('').map(Number));
}
console.log(numberSum(22222)); // 2 + 2 + 2 + 2 + 2 = 10

For the input you have (22222) your function is a practical solution. If you want a function that takes a number and adds itself together a certain number of times you can simply do this...
function sums(a, b) {
return a * b;
}
sums(2, 5);
//=> 10
But if you really require an example of a recursive function to do this the following will achieve the same result...
var num = 2;
var iterate = 5;
function sums(n, count, total) {
if (count === 0) {
return total;
} else {
return sums(n, --count, total+n);
}
}
console.log(sums(num, iterate, 0));
//=> 10
Hope that helped. :)
(See this blog post on JavaScript recursion by integralist).

Related

Higher-order function

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);

Javascript recursive function not return the result

this maybe is not the biggest challenging problem but I've got curious about it.
I did a simple code just to get the Fibonacci value based on the user input without recursion and works just fine. Very simple code:
function fib(n) {
let fibArray = [0,1];
let count = 0;
while(fibArray.length <= n){
let previous = fibArray[count + 1];
let beforePrevious = fibArray[count];
fibArray.push(beforePrevious + previous);
count++;
}
return fibArray[n];
}
But the moment I tried to make it as a recursive function, the result is undefined, even if the value is not.
function fib(n, count = 0, fibArray = [0,1]){
if(fibArray.length - 1 === n){
return fibArray[n];
}
if (fibArray.length <= n ) {
let previous = fibArray[count + 1];
let beforePrevious = fibArray[count];
fibArray.push(beforePrevious + previous);
count++;
}
fib(n,count, fibArray);
}
Just add a return statement in the last line.
return fib(n,count, fibArray);
The code is ok, you just need to add a return:
function fib(n, count = 0, fibArray = [0,1]){
if(fibArray.length - 1 === n){
return fibArray[n];
}
if (fibArray.length <= n ) {
let previous = fibArray[count + 1];
let beforePrevious = fibArray[count];
fibArray.push(beforePrevious + previous);
count++;
}
return fib(n,count, fibArray);
}

Most frequently occuring number (mode) in a list - want to get only the highest value

I'm trying to get whatever number is the most frequently occuring number in an array, so for an array containing 1,2,10,5,1 the result should be 1. The code I wrote returns me the frequency for each number, so 1 occurs twice, 2 occurs once, 10 occurs once etc. Any suggestions how I can fix my result?
function mode(arr) {
var uniqNum = {};
var numCounter = function(num, counter) {
if(!uniqNum.hasOwnProperty(num)) {
uniqNum[num] = 1;
} else {
uniqNum[num] ++;
}
};
arr.forEach(numCounter);
return uniqNum;
}
I've kept your code unchanged and added some extra statements. Here is the demo: http://codepen.io/PiotrBerebecki/pen/rrdxRo
function mode(arr) {
var uniqNum = {};
var numCounter = function(num, counter) {
if(!uniqNum.hasOwnProperty(num)) {
uniqNum[num] = 1;
} else {
uniqNum[num] ++;
}
};
arr.forEach(numCounter);
return Object.keys(uniqNum)
.sort((a,b) => uniqNum[b] - uniqNum[a]) // sort by frequency
.filter((val,ind,array) => uniqNum[array[0]] == uniqNum[val]) // leave only most frequent
.map(val => Number(val)); // convert text to number
}
console.log( JSON.stringify(mode([3,3,2,4,4])) ) // [3,4]
console.log( JSON.stringify(mode([2,4,3,3])) ) // [3]
I think it could be done only with a little modification to your forEach loop and the assistance of another auxiliary data structure:
function mode(arr) {
var freq = [], uniqNum = {}, i;
arr.forEach(function (num) {
uniqNum[num] = i = (uniqNum[num] || 0) + 1;
freq[i] = (freq[i] || []).concat(num);
});
return freq[freq.length - 1];
}
console.log(mode([1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 6, 6, 7, 1, 6]));
With only one iteration over all the elements of the array we can gather enough information to print out the result:
uniqNum is the set you created to gather info about the element's frequency.
freq will be an array which last element will contain an array with the elements of higher frequency.
Fiddle. Hope it helps.
First we want to make an array where we count the number of occurrences of a certain value up to that point.
Then we use the reduce function to return an array of values read from the original array for the indexes whose values have the current max appearances. We redefine max and empty the final output array of modes (if new max is established) as we go along. We want this to be a collection in case there is a tie for maximum appearances.
Additional advantage of the below is that it doesn't require sort which is more expensive o(nlog n) and keeps the time complexity down to just linear. I also wanted to keep the functions used down to only two (map and reduce) as it is all that is need in this case.
edit: fixed a major bug uniqNum[e] += 1 instead of uniqNum[e] + 1 which went unnoticed as my initial case array was still returning expected result. Also made the syntax more concise in favor of more comments.
var arr = [1,2,10,5,1,5,2,2,5,3,3];
//global max to keep track of which value has most appearances.
var max = -1;
var uniqNum = {};
var modeArray = arr.map(function(e) {
//create array that counts appearances of the value up to that point starting from beginning of the input arr array.
if(!uniqNum.hasOwnProperty(e)) {
uniqNum[e] = 1;
return 1;
} else {
return uniqNum[e] += 1;
}
//reduce the above appearance count array into an array that only contains values of the modes
}).reduce(function (modes, e1, i) {
//if max gets beaten then redefine the mode array to only include the new max appearance value.
if(e1 > max){
//redefining max
max = e1;
//returning only the new max element
return [arr[i]];
//if its a tie we still want to include the current value but we don't want to empty the array.
}else if(e1 == max){
//append onto the modes array the co-max value
return[...modes, arr[i]];
}
return modes;
},[]);
alert(modeArray);
Here is a test you can run of my solution against #acontell. In my browser (Chrome with V8) my solution was around three-four times faster for arrays with large number of repeating values and even bigger advantage with distributions with lower number of repeating values. #acontell 's is a cleaner looking solution for sure, but definitely not faster in execution.
var arr = [];
for(var i=0; i < 100000; i++){
arr.push(Math.floor(Math.random() * (100 - 1)) + 1);
}
console.time("test");
test();
function test(){
var max = -1;
var uniqNum = {};
var modeArray = arr.map(function(e) {
//create array that counts appearances of the value up to that point starting from beginning of the input arr array.
if(!uniqNum.hasOwnProperty(e)) {
uniqNum[e] = 1;
return 1;
} else {
return uniqNum[e] += 1;
}
//reduce the above appearance count array into an array that only contains values of the modes
}).reduce(function (modes, e1, i) {
//if max gets beaten then redefine the mode array to only include the new max appearance value.
if(e1 > max){
//redefining max
max = e1;
//returning only the new max element
return [arr[i]];
//if its a tie we still want to include the current value but we don't want to empty the array.
}else if(e1 == max){
//append onto the modes array the co-max value
modes.push(arr[i])
return modes;
}
return modes;
},[]);
}
console.timeEnd("test");
console.time("test1");
test1();
function test1 () {
var freq = [],
uniqNum = {},
i;
arr.forEach(function(num) {
uniqNum[num] = i = (uniqNum[num] || 0) + 1;
freq[i] = (freq[i] || []).concat(num);
});
return freq[freq.length - 1];
}
console.timeEnd("test1");
I've tried as an exercise to solve this with native js functions.
var arr = [1,2,10,5,1];
// groupBy number
var x = arr.reduce(
function(ac, cur){
ac[cur]?(ac[cur] = ac[cur] + 1):ac[cur] = 1;
return ac;
}, {}
);
// sort in order of frequencies
var res = Object.keys(x).sort(
function(a,b){ return x[a] < x[b]}
);
res[0] has the most frequent element

JavaScript: composable self-referential function for counting / obtaining property from bound function

I'm not sure if what I am trying to do is impossible or not.
Consider this function:
function p(num) {
if (!num) num = 1;
return p.bind(null, num + 1);
}
if you call p(), inside the function num = 1, if you call p()(), num = 2 and so on. But, there is no way to actually return or obtain num from p because it always returns a bound copy of itself with the number trapped in its unexecutable closure.
Anyway, I'm curious (a) if there is a way to pull the argument out of the bound function, or (b) there is another way to count in this fashion.
I have two answers depending on what you want. If you simply want something "imperative" and "stateful":
function p() {
if (!p.num) p.num = 0;
p.num = 1 + p.num;
return p;
}
p();
p.num; // 1
p();
p.num; // 2
p()();
p.num; // 4
p()()();
p.num; // 7
Or if you want it to be "stateless":
function p() {
p.num = 0;
function gen_next(prev) {
function next() {
return gen_next(next);
}
next.num = prev.num + 1;
return next;
}
return gen_next(p);
}
p().num; // 1
p()().num; // 2
p()()().num; // 3
p()().num; // still 2
p().num; // still 1

Reverse order of an array and return the size of it javascript

I have a strange problem. I have to implement a function count(s) which inverts the getNumberSequence function that I have already create. (i.e: count(getNumberSequence(x)) == x, for all integers x > 0). I have my function and I have also the logic to resolve the problem but I don't know how to do it. In my case I want to call the previous string of ordered numbers, split them and call the last number. The problem is, how can I call the return of another method? Here are my codes:
function getNumberSequence(number) {
var result = "";
if (number <= 0) {
return result;
} else {
var first = true;
for (i = 1; i <= number; i++) {
if (first) {
first = false;
} else {
result += ", ";
}
result += i;
}
}
return result
}
Basically I need the variable result in this case to call it in the other function.
function count(s) {
var d = s. split(', ');
return d[-1];
}
I know that the second code is wrong but I don't know how to fix it. I have implemented a test that is:
test( "Count", function() {
for (i = 1; i<10000; i = i + 10) {
equal(count(getNumberSequence(i)) , i, "count(getNumberSequence(" +i + ")) should return " + i);
}
I know that the answer could be stupid but I started javascript yesterday for the first time. Hope you can help me. Thanks to everyone
If I understand you correctly you want to pass a number, say 10, into the first function and have that return a string of numbers up to 10 and then for count to read that string and return 10 (as an integer) again? This will do the trick. It takes the string, splits it, and pops out the last number converting it to an integer before it returns it.
function count(seq) {
return parseInt(seq.split(', ').pop(), 10);
}
I could rewrite it like this:
function count(seq) {
// create an array
var arr = seq.split(', ');
// grab the last element (a string)
var lastElement = arr.pop();
// convert the string to an integer
var convertedInteger = parseInt(lastElement, 10);
// return the integer
return convertedInteger;
}
If you wanted to use reverse and grab the first element, do this:
function count(seq) {
return parseInt(seq.split(', ').reverse()[0], 10);
}
Or use shift which does the same thing:
function count(seq) {
return parseInt(seq.split(', ').reverse().shift(), 10);
}
DEMO

Categories