Recursion challenge - Edabit - javascript

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`

Related

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

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

javascript string comparison not returning true for equal strings in console [solved]

I'm working with words and their phonemes. I found that in my code (and in the console) what looks like two identical strings " 'b eh1 r z'" for example are not returning true when compared, whether with double or triple equals. I did sanity tests in the chrome console, in the node console and in the file itself, and they all return expected results (i.e. only the 'strinfigied' variable seems corrupted. I'm racking my brains trying to figure what's going on. This is what is not workign as expected:
let stringified = trialPhonemeSequence.join(" ")
if (p == "z"){
console.log(trialPhonemeSequence)
let bearstring = 'b eh1 r z'
console.log("SHould be adding 'z' at ", i, "so we got", trialPhonemeSequence, "and stringified", stringified)
console.log(`String|${dictionary['bears']}| length ${dictionary['bears'].length} should equal |${stringified}| length ${stringified.length}: ${dictionary['bears'] == stringified} and ${bearstring == stringified}`);
}
What the Chrome Console outputs
String|b eh1 r z| length 10 should equal |b eh1 r z| length 10: false and false
Here is the entire function up to that point for context. I don't think you want the entire min reproduable code as it requires large dictionaries and datasets and initialization. The goal of this function was to input bear and look for words that are a phonemic match, allowing for addition of a phoneme (the 'z' sound in this test case).
function findAddedPhonemes(word, dictionary, hashMap)
{
let matches = []
let phonemeSequence = dictionary[word]
let phonemeSequenceList = phonemeSequence.split(" ")
for (let i = 0; i <= phonemeSequenceList.length; i++)
{
phonemeList.forEach((p, ind) => // all the items in the list
{
let trialPhonemeSequence = phonemeSequenceList.slice()
trialPhonemeSequence.splice(i, 0, p) // insert p phoneme into index
let stringified = trialPhonemeSequence.join(" ")
if (p == "z"){
console.log(trialPhonemeSequence)
let bearstring = 'b eh1 r z'
console.log(`String|${dictionary['bears']}| length ${dictionary['bears'].length} should equal |${stringified}| length ${stringified.length}: ${dictionary['bears'] == stringified} and ${bearstring == stringified}`);
}
if (stringified == "b eh1 r z"){ //THIS IS WHERE ITS BROKEN
console.log("Bears stringified searching!!!!!!!!!!!!")
}
let hash = stringified.hashCode(dictKeys.length * 4)
if (hashMap[hash] !== undefined)
{
hashMap[hash].forEach((o) =>
{
let key = getObjectsKey(o)
if (checkIfIdentical(dictionary[key], stringified))
{
matches.push(key)
}
})
}
})
}
console.log("Matches", matches)
return matches
}
EDIT (SOLVED):
There is a char 13 (Carriage Return) in Stringified string but not the others. I think I understand where this is coming from. I was inserting a new phoneme with splice in each syllable of the word, and when splicing it onto the end of the words, it's not automatically stripping the '\n', which results in comparison errors. I now know one has to do this manually and wrong hash values. BTW the phoneme dictionary ishere
Thanks #VLAZ !
stringified.split("").map(c => {
console.log(c.charCodeAt(0))
})
console.log("New word")
bearstring.split("").map(c => {
console.log(c.charCodeAt(0))
})
console.log(stringified==bearstring)

Convert camel case to sentence case in javascript

I found myself needing to do camel case to sentence case string conversion with sane acronym support, a google search for ideas led me to the following SO post:
Convert camelCaseText to Sentence Case Text
Which is actually asking about title case not sentence case so I came up with the following solution which maybe others will find helpful or can offer improvements to, it is using ES6 which is acceptable for me and can easily be polyfilled if there's some horrible IE requirement.
The below uses capitalised notation for acronyms; I don't agree with Microsoft's recommendation of capitalising when more than two characters so this expects the whole acronym to be capitalised even if it's at the start of the string (which technically means it's not camel case but it gives sane controllable output), multiple consecutive acronyms can be escaped with _ (e.g. parseDBM_MXL -> Parse DBM XML).
function camelToSentenceCase(str) {
return str.split(/([A-Z]|\d)/).map((v, i, arr) => {
// If first block then capitalise 1st letter regardless
if (!i) return v.charAt(0).toUpperCase() + v.slice(1);
// Skip empty blocks
if (!v) return v;
// Underscore substitution
if (v === '_') return " ";
// We have a capital or number
if (v.length === 1 && v === v.toUpperCase()) {
const previousCapital = !arr[i-1] || arr[i-1] === '_';
const nextWord = i+1 < arr.length && arr[i+1] && arr[i+1] !== '_';
const nextTwoCapitalsOrEndOfString = i+3 > arr.length || !arr[i+1] && !arr[i+3];
// Insert space
if (!previousCapital || nextWord) v = " " + v;
// Start of word or single letter word
if (nextWord || (!previousCapital && !nextTwoCapitalsOrEndOfString)) v = v.toLowerCase();
}
return v;
}).join("");
}
// ----------------------------------------------------- //
var testSet = [
'camelCase',
'camelTOPCase',
'aP2PConnection',
'JSONIsGreat',
'thisIsALoadOfJSON',
'parseDBM_XML',
'superSimpleExample',
'aGoodIPAddress'
];
testSet.forEach(function(item) {
console.log(item, '->', camelToSentenceCase(item));
});

Please explain this recursive javascript function

I was in codewars this morning and there is this Kata asking for a function to reverse a string passed as parameter through recursion method.
The best solution listed for this problem was this.
function reverse(str) {
return str.length > 1 ? reverse(str.slice(1)) + str[0] : str;
}
I researched for this all this morning and I still don't know what is happening here:
+ str[0]
Can somebody please clarify this for me?
The essence of the function is the following:
Take the substring from the second character to the last
Apply the reverse function recursively
Take the first character and append it to the end of the result of the recursive call
Return the result
This results in the following logic, the (recursive) function calls indicated by brackets:
(A B C D E)
((B C D E) A)
(((C D E) B) A)
((((D E) C) B) A)
(((((E) D) C) B) A)
str.slice(1) "chops off" the first letter of the string and returns the rest of it. So 'abcd'.slice(1) gives you 'bcd'.
str[0] is the first letter of the string. 'abcd'[0] is 'a'.
So, str.slice(1) + str[0] is taking the first letter of the string and "moving" it to the end: 'abcd' becomes 'bcda'.
This does not address the recursive nature of the solution, but it answers your question about + str[0].
I'll try to rewrite the function in a more "human-readable" way
reverse = str => {
// If there is still string to reverse
if (str.length > 1) {
let firstChar = str[0]
let strWithoutFirstChar = str.slice(1)
// Notice only a part of the string 'comes back' here
// console.log(strWithoutFirstChar) // Might help
return reverse(strWithoutFirstChar) + firstChar
}
// Else return result as is
else {
return str
}
}
This is the same function, but without ternaries and declaring well named variables.
If you uncomment the console.log() line and call:
reverse('help');
The output should be:
elp
lp
p
'pleh'
Hope it helps!
The + operator is a concatenator for string.
You can instead use concat this :
var reverse = str => str.length > 1 ? reverse(str.slice(1)).concat(str[0]) : str;
console.log(reverse("123456789")); // 987654321

Anything similar in javascript to ruby's #{value} (string interpolation) [duplicate]

This question already has answers here:
How can I do string interpolation in JavaScript?
(21 answers)
Closed 8 years ago.
i am tired of writing this:
string_needed="prefix....." + topic + "suffix...." + name + "testing";
i would think someone might have done something about this by now ;)
ES6 Update:
ES6 added template strings, which use backticks (`) instead of single or double quotes. In a template string, you can use the ${} syntax to add expressions. Using your example, it would be:
string_needed = `prefix.....${topic}suffix....${name}testing`
Original answer:
Sorry :(
I like to take advantage of Array.join:
["prefix ....", topic, "suffix....", name, "testing"].join("")
or use String.concat
String.concat("a", 2, "c")
or you could write your own concatenate function:
var concat = function(/* args */) {
/*
* Something involving a loop through arguments
*/
}
or use a 3rd-party sprintf function, such as http://www.diveintojavascript.com/projects/javascript-sprintf
You could consider using coffeescript to write the code (which has interpolation like Ruby ie #{foo}).
It 'compiles' down to javascript - so you will end up with javascript like what you've written, but without the need to write/maintain the +++ code you're tired of
I realize that asking you to consider another language is on the edge of being a valid answer or not but considering the way coffeescript works, and that one of your tags is Ruby, I'm hoping it'll pass.
As a Javascript curiosity, you can implement something that basically does Ruby-like interpolation:
sub = function(str) {
return str.replace(/#\{(.*?)\}/g,
function(whole, expr) {
return eval(expr)
})
}
js> y = "world!"
world!
js> sub("Hello #{y}")
Hello world!
js> sub("1 + 1 = #{1 + 1}")
1 + 1 = 2
Using it on anything but string literals is asking for trouble, and it's probably quite slow anyways (although I haven't measured). Just thought I'd let you know.
Direct answer: No javascript doesn't support string interpolation.
The only way is to implement it yourself or use a third party lib who does it for you.
EDIT
As Marcos added in comments theres a proposal for ECMAScript 6 (Harmony), so we can have proper string interpolation:
var a = 5;
var b = 10;
console.log(`Fifteen is ${a + b} and\nnot ${2 * a + b}.`);
// "Fifteen is 15 and
// not 20."
Please see more information here.
I just wrote this hacky function to do this. Usage is as follows:
interpolate("#{gimme}, #{shelter}", {gimme:'hello', shelter:'world'})
// returns "hello, world"
And the implementation:
interpolate = function(formatString, data) {
var i, len,
formatChar,
prevFormatChar,
prevPrevFormatChar;
var prop, startIndex = -1, endIndex = -1,
finalString = '';
for (i = 0, len = formatString.length; i<len; ++i) {
formatChar = formatString[i];
prevFormatChar = i===0 ? '\0' : formatString[i-1],
prevPrevFormatChar = i<2 ? '\0' : formatString[i-2];
if (formatChar === '{' && prevFormatChar === '#' && prevPrevFormatChar !== '\\' ) {
startIndex = i;
} else if (formatChar === '}' && prevFormatChar !== '\\' && startIndex !== -1) {
endIndex = i;
finalString += data[formatString.substring(startIndex+1, endIndex)];
startIndex = -1;
endIndex = -1;
} else if (startIndex === -1 && startIndex === -1){
if ( (formatChar !== '\\' && formatChar !== '#') || ( (formatChar === '\\' || formatChar === '#') && prevFormatChar === '\\') ) {
finalString += formatChar;
}
}
}
return finalString;
};

Categories

Resources