How can I recurse in JS to repeat a string n times? - javascript

I am trying to make the code below repeat string s n number of times, however, it will always repeat n - 1 times, because I need to pass a decrement to exit the recursion or I will exceed the max call stack.
function repeatStr (n, s) {
while(n > 1) {
result = repeatStr(-n, s)
return s = s.concat(s)
}
}
repeatStr(3, "Hi")
What can I change to make it recurse correctly?

Recursion involves making a function call itself and AVOIDS using a loop. You have a loop in the recursive function which is a big red flag.
Do something like this:
If n is 1 return s else return s concatenated to the result of the function with n - 1.
function repeatStr (n, s) {
if (n == 1)
return s;
else
return s.concat(repeatStr(n - 1, s))
}
repeatStr(3, "Hi")

Because you're new to programming and JavaScript, let's work up to the solution. Start with a simple case, e.g. repeatStr(3, "Hi"). One simple answer may be:
function repeatStr(n, s) {
return "HiHiHi";
}
Here, we assume what the inputs are always 3 and "Hi". We don't have a while loop, and we don't have recursion. We have the correct answer for those specific inputs but no other inputs are supported.
Let's make the answer a little bit harder:
function repeatStr(n, s) {
return "Hi" + "Hi" + "Hi";
}
Here, again, we are assuming the inputs are 3 and "Hi". We still don't have a while loop nor do we have recursion.
Okay, let's start using one of your inputs:
function repeatStr(n, s) {
return s + s + s;
}
Here, we are finally using the string that's passed in as s. We can handle inputs other than "Hi" to generate a correct answer. But, we're still assuming the number input is 3.
Finally, let's have a look at n:
function repeatStr(n, s) {
let result = "";
while (n > 0) {
n = n - 1;
result = result + s;
}
return result;
}
Okay, here we take both inputs n and s into consideration and we solve the problem by appending s exactly the number n times needed. This is a while loop solution, not a recursion solution. Our while loop has the action result = result + s; repeated exactly n times where we use n as a countdown and stop when we reach 0.
Now, we have all that background, let's look at one version of the recursion solution.
function repeatStr(n, s) {
if (n <= 0) {
return "";
}
return s + repeat(n - 1, s);
}
Even in recursion form we retain the countdown feature. This time the countdown is used to drive the recursion instead of a while loop. We still counting down to 0 where we have an if-return guard condition that's needed to terminate the recursion. i.e. when n <= 0, we exit with the simple empty string "". Then for the more complex case, it is solving any nth version by expressing in terms of the (n-1) th version. Another way of looking at it is this:
repeatStr(3, "Hi") === "Hi" + repeatStr(2, "Hi")
=== "Hi" + "Hi" + repeatStr(1, "Hi")
=== "Hi" + "Hi" + "Hi" + repeatStr(0, "Hi")
=== "Hi" + "Hi" + "Hi" + ""
If you want to get a little clever, JavaScript has a conditional which can be used in place of your if statement:
function repeatStr(n, s) {
return (n <= 0) ? "" : s + repeat(n - 1, s);
}
Hope that makes sense.

Adding a decomposed approach to the other nice answers in this thread -
const concat = a => b =>
a.concat(b)
const repeat = n => f =>
x => n && repeat(n - 1)(f)(f(x)) || x
const hello =
repeat(3)(concat("Hi"))
console.log(hello("Alice"))
console.log(hello(""))
HiHiHiAlice
HiHiHi

Related

Javascript: Get nth character of string (JSChallenger)

I am a total newbie and currently learning Javacript.
I encountered this problem on JSChallenger and have been struggling with it.
Here's my code:
// Write a function that takes a string (a) and a number (n) as argument
// Return the nth character of 'a'
function myFunction(a, n)
{let string = a;
let index = n;
return string.charAt(index);
}
Can anyone point out my errors?
Thanks so much!
Here's a very short solution
function find( a, b){
return a[b]
}
console.log(find('how',1));
although you need to do some tests in the function to check if the input for b is greater than the length of a else it would fail.
You can do that like this
function find( a, b){
if(a.length<b-1){
return 'error';
}
return a[b]
}
console.log(find('how',5));
that way your code would be free from error
Try this one
function myFunction(a, n){
return a[n - 1];}
// there is a shorter way to do this since you want to find what's missing here is what's missing.
function myFunction(a, n){
let string = a;
let index = n-1;
return string.charAt(index);
}
JS string's index starts enumerating from 0 so the n should be decremented by 1
// Write a function that takes a string (a) and a number (n) as argument
// Return the nth character of 'a'
function myFunction(a, n)
{
let string = a;
let index = n;
return string.charAt(index-1);
}
the easiest way to write it would be:
// Write a function that takes a string (a) and a number (n) as argument
// Return the nth character of 'a'
function myFunction(a,n) {
return a[n - 1];
}
Meaning return from string "a" of myFunction the index "[n-1]" , "n-1" it's a needed operation to get the right index because string index start enumerating from 0.
It is very easy you can just return the a[n]
but it is not the right answer because as you know the strings in JavaScript are zero-indexed so the right answer is
function myFunction(a, n) {
return a[n - 1]
}
Happy Coding & keep Learning
also this solution works too, with empty space at first of string we can remove that counting from zero :
function myFunction(a, n) {
return ` ${a}}`[n]
}
but this is just another solution. not tested. and you can check this repo for other JSchallenger solutinos: JSchallenger solutions
in javascript, you can write this simple code to solve your problem
ex:
let string = "Hello";
let n = 2;
return string[n];
function myFunction(a, n) {
return a.charAt(n - 1);
}
console.log(myFunction("hello", 2));
I think so this is best way
that is a tricky question if you look to the test cases you will notice that it ignore counting from zero
function myFunction(a, n) {
return a.charAt(n-1);
}

A task in JavaScript

I need to create a sequence of numbers using while or for that consists of the sum of the symbols of the number.
For example, I have a sequence from 1 to 10. In console (if I've already written a code) will go just 1, 2,3,4,5,6,7,8,9,1. If I take it from 30 to 40 in the console would be 3,4,5,6,7,8,9,10,11,12,13.
I need to create a code that displays a sum that goes from 1 to 100. I don't know how to do it but in console I need to see:
1
2
3
4
5
5
6
7
8
9
1
2
3
4
etc.
I've got some code but I got only NaN. I don't know why. Could you explain this to me?
for (let i = '1'; i <= 99; i++) {
let a = Number(i[0]);
let b = Number(i[1])
let b1 = Boolean(b)
if (b1 == false) {
console.log ('b false', a)
}
else {
console.log ('b true', a + b)
}
}
I hope you get what I was speaking about.
Although I like the accepted answer however from question I gather you were asking something else, that is;
30 become 3+0=3
31 become 3+1=4
37 becomes 3+7=10
Why are we checking for boolean is beyond the scope of the question
Here is simple snnipet does exactly what you ask for
for (let i = 30; i <= 40; i++) {
let x=i.toString();
console.log( 'numbers from ' +i + ' are added together to become '+ (Number(x[0])+Number((x[1])||0)))
}
what er are doing is exactly what Maskin stated begin with for loop then in each increment convert it to string so we can split it, this takes care of NAN issue.
you don't need to call to string just do it once as in let x then simply call the split as x[0] and so on.
within second number we have created a self computation (x[1])||0) that is if there is second value if not then zero. following would work like charm
for (let i = 1; i <= 10; i++) {
let x=i.toString();
console.log( 'numbers from ' +i + ' are added together to become '+ (Number(x[0])+Number((x[1])||0)))
}
Did you observe what happens to ten
here is my real question and solution what if you Don't know the length of the digits in number or for what ever reason you are to go about staring from 100 on wards. We need some form of AI into the code
for (let i = 110; i <= 120; i++) {
let x= Array.from(String(i), Number);
console.log(
x.reduce(function(a, b){ return a + b;})
);
};
You simply make an array with Array.from function then use simple Array.reduce function to run custom functions that adds up all the values as sum, finally run that in console.
Nice, simple and AI
You got NaN because of "i[0]". You need to add toString() call.
for (let i = '1'; i <= 99; i++) {
let a = Number(i.toString()[0]);
let b = Number(i.toString()[1])
let b1 = Boolean(b)
if (b1 == false) {
console.log('b false', a)
} else {
console.log('b true', a + b)
}
}
So the way a for loop works is that you declare a variable to loop, then state the loop condition and then you ask what happens at the end of the loop, normally you increment (which means take the variable and add one to it).
When you say let i = '1', what you're actually doing, is creating a new string, which when you ask for i[0], it gives you the first character in the string.
You should look up the modulo operator. You want to add the number of units, which you can get by dividing by 10 and then casting to an int, to the number in the tens, which you get with the modulo.
As an aside, when you ask a question on StackOverflow, you should ask in a way that means people who have similar questions to you can find their answers.

Recursion challenge - Edabit

The problem wants me to output the string "Edabit" with the number of "a" characters equaling the initial number passed through the function.
I have tried different methods of concatenation but for some reason the string of "a"s seem to ignore their place in the concatenation.
function howManyTimes(num) {
let str = ''
if (num === 0){
return `Ed${str}bit`
}
else {
str += 'a'
return str += howManyTimes(num - 1)
}
}
console.assert(howManyTimes(0) == "Edbit", "1. Instead got "+howManyTimes(0));
console.assert(howManyTimes(1) == "Edabit", "2. Instead got "+howManyTimes(1));
console.assert(howManyTimes(10) == "Edaaaaaaaaaabit", "3. Instead got "+howManyTimes(10));
function howManyTimes(num, str) {
if (!str) str = '';
if (num > 0) {
return howManyTimes(num - 1, str + 'a');
} else {
return `Ed${str}bit`;
}
}
console.log(howManyTimes(8));
One issue is that your recursion is always appending the result of the method to an a. Rather than doing that, pass along the aggregated string to then be used once you reach the end.
You can always separate out the part that can use straightforward recursion from a shell that calls that part and does something with the result. For instance,
const nAs = (n) =>
n == 0 ? '' : nAs (n - 1) + 'a'
const howManyTimes = (n) =>
`Ed${nAs (n)}bit`
console .log (howManyTimes (0))
console .log (howManyTimes (1))
console .log (howManyTimes (10))
Of course I would only write it this way in a recursion challenge. For this example, there are more straightforward ways to write this, including const howManyTimes = (n) => `Ed${'a'.repeat(n)}bit`

JavaScript: Write a function that takes an input character and returns that character repeated 5 times using recursion

Write a function that takes an input character and returns that character repeated 5 times using recursion. For example, if the input is 'g', then the output should be 'ggggg'.
I tried the code below:
function repeater(char) {
let newStr = '';
if (newStr.length === 5){
return newStr;
}
else {
newStr += char;
}
return repeater(char);
}
// To check if you've completed the challenge, uncomment these console.logs!
console.log(repeater('g')); // should return 'ggggg'
//console.log(repeater('j')); 'jjjjj'
My code returns: RangeError: Maximum call stack size exceeded
What am I doing wrong?
Cause newStr is a local variable that does not get passed on in the recursive call. Therefore, a new newStr will be created on each call, and its length will always be 0. To resolve that, either pass on the string, or the length:
function repeat(char, result = "") {
if(result.length / char.length >= 3) return result;
return repeat(char, result + char); // ²
}
// a call goes like:
// repeat("g", "")
// repeat("g", "g")
// repeat("g", "gg")
// repeat("g", "ggg")
// OR
function repeat(char, count = 3) { /*¹*/
if(count <= 1) return char;
return char + repeat(char, count - 1);
}
// repeat("g", 3)
// "g" + repeat("g", 2)
// "g" + "g" + repeat("g", 1)
// "g" + "g" + "g"
Or if this should only work with one char given (as the task says):
function repeat(char) {
if(char.length >= 3) return char;
return repeat(char + char[0]); // ²
}
Note: The functions above won't return 5 repeats. Thats left as an exercise to you :)
If we take the assignment aside you could just do "g".repeat(5) though ...
¹: The = 3 is a so called "default argument". That means that repeat("g") equals repeat("g", 3). The advantage is that you can reuse this for different lengths, repeat("g", 10) will repeat g 10 times.
²: Thats a tail call. If you place the recursive call at the last line and return it, the engine can optimize the recursion into a loop, which is way faster and does not reach a maximum call stack size (infinite recursion is still bad, try to always avoid getting into it. newStr.length === 5 for example is dangerous, as a string of length 6 would run forever. Therefore I'd recommend using >= or <= (as I did above)).
You could take a default value of 5 and call the recursion until no more calls are a available.
function repeater(char, count = 5) {
if (!count) return ''; // exit condition
return char + repeater(char, count - 1); // repeating part
}
console.log(repeater('x'));
One thing in your code is you are calling repeater outside else condition which means it will be called infinitely. Second is you are declaring newStr inside the function. You may want to do something like this.
function repeater(char, oldStr) {
let newStr = oldStr || '';
if (newStr.length === 5) {
return newStr;
} else {
newStr += char;
return repeater(char, newStr);
}
}

Why does this JavaScript function work?

Much apologies for the vague title, but I need to elaborate. Here is the code in question, which I read on http://ariya.ofilabs.com/2013/07/prime-numbers-factorial-and-fibonacci-series-with-javascript-array.html:
function isPrime(i) {
return (i > 1) && Array.apply(0, Array(1 + ~~Math.sqrt(i))).
every(function (x, y) {
console.log(x + ' ' + i % y);
return (y < 2) || (i % y !== 0)
});
}
isPrime(23);
isPrime(19);
isPrime(188);
Just for fun, I added those logs so we can see some output:
undefined NaN
undefined 0
undefined 1
undefined 2
undefined 3
undefined NaN
undefined 0
undefined 1
undefined 1
undefined 3
undefined NaN
undefined 0
undefined 0
This is the first time I have every seen apply and every, so bear with me, but my understanding is that apply basically calls the Array function, where the first argument is the substitution for its this and the second is the output...Never would think that would be useful, but this function seems to work, so...
Here, they seem to be creating an array of length equal to the square root of the number in question. I suppose that makes sense because the square root would be the largest possible factor of the number in question.
OK, so from here, if we were to log that array for, say, the first number, it would look like this:
> var i = 23;
undefined
> Array.apply(0, Array(1 + ~~Math.sqrt(i)));
[ undefined, undefined, undefined, undefined, undefined ]
Great, so it is an array of five undefined. Ok, fine, so from here, the every method is supposed to check whether every element in that array passes the callback function test (or whatever).
The Microsoft documentation specifies three possible arguments for the every method:
value
index
array
Therefore, in this example x is the value, i.e. undefined, and y is the index.
Our output agrees with that conclusion. However, I'm still fuzzy about nested return statements (if the lowest one returns, does its parent also return?), the || operator here (if the first test passes, does the every loop stop?), and just generally how this works.
EDIT
the log should be with an x, not a y. my mistake:
console.log(y + ' ' + i % y); -> console.log(x + ' ' + i % y);
EXPLANATION
So, how did I come across this code, you ask? Well, of course, the simplest way to check for a prime in Java would be like this:
public static boolean isPrime(double num) {
for (double i = 2.0; i < sqrt(num); i++) {
if (num % i == 0.0) {
return true;
}
}
return false;
}
or Python
def isPrime(num):
x = 2
isPrime = True
while x < math.sqrt(num):
if num % x == 0:
isPrime = False
break
x = x + 1
return isPrime
or js
function isPrime(n) {
for (var i = 2.0; i < Math.sqrt(n); i++) {
if (n % i === 0.0) {
return false;
}
}
return true;
}
But say I wanted to check for the largest prime factor of a number like 600851475143 These looping methods would take too long, right? I think this "hack", as we are describing it, may be even less efficient, because it is using arrays instead of integers or floats, but even still, I was just looking for a more efficient way to solve that problem.
The code in that post is basically crap. Teaching people to write code while simultaneously using hacks is garbage. Yes, hacks have their place (optimization), but educators should demonstrate solutions that don't depend on them.
Hack 1
// the 0 isn't even relevant here. it should be null
Array.apply(0, Array(1 + ...))
Hack 2
// This is just Math.floor(x), but trying to be clever
~~x
Hack 3
// this is an outright sin; totally unreadable code
// I bet most people don't know the binding precedence of % over +
y + ' ' + i % y
// this is evaluated as
y + ' ' + (i % y)
// example
2 + ' ' + (5 % 2) //=> "2 1"
I'm still fuzzy about nested return statements (if the lowest one returns, does its parent also return?),
No. A return only return the function the statement exists in
the || operator here (if the first test passes, does the every loop stop?)
No. Array.prototype.every will return false as soon as the callback returns a false. If a false is never returned from the callback, .every will return `true.
function isEven(x) { return x % 2 === 0; }
[2,4,5,6].every(isEven); //=> false, stops at the 5
[2,4,6].every(isEven); //=> true
Here's an example of .every short circuiting
[1,2,3,4,5,6].every(x=> {console.log(x, x<4); return x<4;});
// 1 true
// 2 true
// 3 true
// 4 false
//=> false
See how it stops once the callback returns false? Elements 5 and 6 aren't even evaluated.
... and just generally how this works.
&& kind of works like Array.prototype.every and || kind of works like Array.prototype.some.
&& will return false as soon as the first false is encountered; in other words, it expects every arguments to be true.
|| will return true as soon as the first true is encountered; in other words, it expects only some argument to be true.
Relevant: short circuit evaluation

Categories

Resources