JavaScript, brackets on for loop causing errors? - javascript

I have a function that takes an input of a string and a single char that will count how many times that char appears in that string.
function count(str, letter) {
var num = 0;
for (var i = 0; i < str.length; i++)
if (str.charAt(i) == letter)
num += 1;
return num;
}
console.log(count("BBC", "B"));
//output 2
It works fine like this, but this took me some time to figure out. Its second hand nature for me to always put brackets on a for loop but when i do that, the function doesn't work as i anticipated it would, like so:
function count(str, letter) {
var num = 0;
for (var i = 0; i < str.length; i++) {
if (str.charAt(i) == letter)
num += 1;
return num;
}
}
console.log(count("BBC", "B"));
//outputs 1
Why are the brackets causing it to act this way?

Why are the brackets causing it to act this way?
Because you have the return statement inside of the for loop block. At the end of the block, the function returns.
function count(str, letter) {
var num = 0;
for (var i = 0; i < str.length; i++) { // block start
if (str.charAt(i) == letter)
num += 1;
return num; // exit function in first loop
} // block end
}

It's not the braces (brackets are []), it's the placement of the return statement. The return statement is in the first iteration of the loop (i = 0). If you add an extra set of braces (as seen below), it becomes more obvious.
function count(str, letter) {
var num = 0;
for (var i = 0; i < str.length; i++) {
if (str.charAt(i) == letter) {
num += 1;
}
return num; // <-- This return exits the function
}
}
console.log(count("BBC", "B"));
//outputs 1

In the First one return statement was outside for loop, but in the second one return statement is inside the for loop. That made the difference.
Try the below code.
function count(str, letter) {
var num = 0;
for (var i = 0; i < str.length; i++) {
if (str.charAt(i) == letter)
num += 1;
}
return num;
}
console.log(count("BBC", "B"));

your loop gets terminated after first iteration.
So if you try to get the occurrence of "B" in "XBBBB...B" it will return 0.
Try to debug your code and place brackets at right position.
Learn to debug your js code using browser.

Related

The only word that is not passing the test is "almostomla."

I am learning JS on freecodecamp and am stuck on a problem. I am creating a palindrome checker. My code almost works. However, there is only one word that is not passing the test and that is almostomla. It is not a palindrome yet my code returns true. I have tried several things. Even rewrote the code and used the while loop but nothing seems to help. There is a solution at the freeCodecamp web but I have written the code in a different way and am unable to figure my mistake out.
Here is my code.
let reversedStr = [];
function palindrome(str) {
let d = str.replace(/[^a-zA-Z0-9]/g, "").toLowerCase();
for (let i = d.length - 1; i >= 0; i--) {
reversedStr.push(d[i]);
}
for (let j = 0; j < str.length; j++) {
if (reversedStr[j] == d[j]) {
return true;
} else {
return false;
}
}
}
console.log(palindrome("almostomla"));
This line if (reversedStr[j] == d[j]) {return true; returns as soon as the character matches at both the index. It does not check rest of the characters.
In fact you can just return as soon as the character in both index does not match.
Also note the reversedStr has to be inside the function. Else it will contain previous values
function palindrome(str) {
let reversedStr = [];
let d = str.replace(/[^a-zA-Z0-9]/g, "").toLowerCase();
for (let i = d.length - 1; i >= 0; i--) {
reversedStr.push(d[i]);
}
for (let j = 0; j < str.length; j++) {
if (reversedStr[j] !== d[j]) {
return false;
}
}
return true
}
console.log(palindrome("almostomla"));
console.log(palindrome("1221"));
Your code returns "true" or "false" after first match - it checks that 'a' is equal to 'a' and returns true.
You can return "false" from inside of cycle only if you found duplicated letter else return true after the cycle ends.

why my code doesn't work when I am trying to concatenate a function's return value with a string?

So, in this code I have a string of 0's and 1's and the length of the string is 32, which will be split in 6 equal parts but the last part will have the length of 2 so I will add (4) 0's after that which will make its length 6. So I wrote a function that will add the remaining 0's which is padding(num).
And that function will be invoked in side the slicing(str) function.
But the code breaks when I try to do execute.
Any help?
Thanks.
// This code works.
function padding0s(num) {
let s = "";
for (i = 0; i < 6 - num; i++) {
s += "0";
}
return s;
}
function slicing(str) {
let k = 6;
let res = [];
let temp1 = 0;
let f = padding0s(2);
for (i = 0; i < str.length; ) {
res.push(str.slice(i, k));
i += 6;
k += 6;
if (res[temp1].length !== 6) {
res[temp1] += f;
}
temp1++;
}
console.log(res);
}
slicing("01000011010011110100010001000101");
// But this does not..
function padding0s(num) {
let s = "";
for (i = 0; i < 6 - num; i++) {
s += "0";
}
return s;
}
function slicing(str) {
let k = 6;
let res = [];
let temp1 = 0;
for (i = 0; i < str.length; ) {
res.push(str.slice(i, k));
i += 6;
k += 6;
if (res[temp1].length !== 6) {
let f = padding0s(res[temp1].length);
res[temp1] += f;
}
temp1++;
}
console.log(res);
}
slicing("01000011010011110100010001000101");
Always define variables before using them
Not doing so can result in undefined behaviour, which is exactly what is happening in your second case. Here is how:
for (i = 0; i < str.length; ) {...}
// ^ Assignment to undefined variable i
In the above for-loop, by using i before you define it, you are declaring it as a global variable. But so far, so good, as it doesn't matter, if not for this second problem. The real problem is the call to padding0s() in your loop. Let's look at padding0s:
function padding0s(num) {
...
for (i = 0; i < 6 - num; i++) {
s += "0";
}
}
This is another loop using i without defining it. But since i was already defined as a global variable in the parent loop, this loop will be setting its value. So in short, the value of i is always equal to 6 - num in the parent loop. Since your exit condition is i < str.length, with a string of length 32 the loop will run forever.
You can get around this in many ways, one of which you've already posted. The other way would be to use let i or var i instead of i in the parent loop. Even better is to write something like this (but beware that padEnd may not work on old browsers):
function slicing(str) {
return str.match(/.{1,6}/g).map((item) => {
return item.padEnd(6, "0");
});
}
console.log(slicing("01000011010011110100010001000101"));

Codewars Javascript Problem- my code with a double for loop times out

I'm trying to solve a problem on Codewars which involves seeing if one string includes all the letters in a second string. I think I've found a decent solution, but my code times out (12000ms) and I can't figure out why. Could anyone shed some light on this issue?
function scramble(str1, str2) {
let i;
let j;
let x = str2.split();
for (i = 0; i < str1.length; i++) {
for (j = 0; j < str2.length; j++) {
if (str1[i] == str2[j]) {
x.splice(j, 1);
j--;
}
}
}
if (x.length == 0) {
return true;
} else {
return false;
}
}
If your strings have sizes N and M then your algorithm is O(N*M). You can get O(NlogN + MlogM) by sorting both strings and then do a simple comparison. But you can do even better and get O(N+M) by counting the letters in one string and then see if they are present in the other. E.g. something like this:
function scramble(str1, str2) {
let count = {}
for (const c of str1) {
if (!count[c])
count[c] = 1
else
count[c]++
}
for (const c of str2) {
if (!(c in count))
return false
count[c]--
}
for (let k in count) {
if (count.hasOwnProperty(k) && count[k] !== 0)
return false
}
return true
}
You created an infinite loop by both incrementing and decrementing j. The value of j gets stuck whenever str1[i] == str2[j]
Reducing your code snippet to the simplest form would look something like this:
for (j = 0; j < 10; j++) {
j--;
console.log(j) // always -1
}
You're adjusting x but then referring to str2 as if it has been changed. Because you never adjust str2, you're always comparing the same two letters, so you get stuck in a loop. That's one problem. Then, your question's wording suggests that we're checking if every letter in str2 is in str1, but you're going through every letter in str1 and checking it against str2. str1 should be the inner loop.
function scramble(str1, str2) {
var x = str2.split("");
for (var i = 0; i < x.length; i++) {
for (var j = 0; j < str1.length; j++) {
if (str1[j] == x[i]) {
x.splice(i--, 1);
}
}
}
return x.length === 0;
}
console.log(scramble("dirty rooms", "dormitory"));
console.log(scramble("cat", "dog"));
Because x.length === 0 is already a boolean value, you can just return that. No need for the if statements there. The triple equals checks the variable's type and value, and double equals only checks value. I tend to always use triple when I'm checking against 0 and 1 because you don't want unintended consequences like this:
console.log(false == 0, true == 1);
console.log(false === 0, true === 1);
Also, because i-- means "i = i - 1 after execution", you can put that directly in your call to splice, and it won't execute until after splice is finished. --i, on the other hand, would be evaluated before execution.
This is all great, but using indexOf is a simpler solution:
function scramble(str1, str2) {
for (let i = 0; i < str2.length; i++) {
if (str1.indexOf(str2[i]) == -1) return false;
}
return true;
}
console.log(scramble("forty five", "over fifty"));
console.log(scramble("cat", "dog"));

function that checks the number of times a character is used in a string

I'm writing a function that takes a string as an argument, checks it for a given character (say "B" in this case), and then returns an integer that reflects the number of times that character appeared. I'm aware that this can be done using regex and such, but the tutorial I'm using has so far made no mention of regex. Code time:
function countBs(string) {
var i = 0;
var n = 0;
var position = string.charAt(n);
while (i < string.length) {
if (string.charAt(n) == "B")
n += 1;
i++; //This line causes the following else statement to throw a syntax error. But it's the only way I can think of to have the loop continue iteration *while* checking for equivalence to "B"
else
i++;
return n;
}
}
And then check with console.log(countBs("ABBA"));
Your code is quite broken.
function countBs(string) {
var i = 0;
var n = 0;
// var position = string.charAt(n); // REMOVE--NOT NECESSARY
while (i < string.length) {
if (string.charAt(i) == "B") // i, NOT n
n++; // CONSISTENCY IN ADD-ONE SYNTAX
// i++; // INCREMENT ONCE BELOW
//else
i++;
}
return n; // MUST GO OUTSIDE THE LOOP
}
Correct code would therefore be:
function countBs(string) {
var i = 0;
var n = 0;
while (i < string.length) {
if (string.charAt(i) == "B") n++;
i++;
}
return n;
}
There's nothing particularly wrong with using a while loop, but a for would be more natural:
function countBs(str) {
var n = 0;
for (var i = 0; i < str.length; i++) if (str[i]== "B") n++;
return n;
}
Modern JS
For your reference, in modern JS, you could avoid the loops and variables. First, let's write a separate checking function:
function isB(c) { return c === 'B'; }
Then write
function countBs(str) {
return str . split('') . filter(isB) . length;
}
or, using reduce:
function countBs(str) {
return str.split('').reduce(function(cnt, c) {
return cnt + isB(c);
}, 0);
}
or, although you said you didn't want to use regexps:
function countBs(str) {
return (str.match(/B/g) || []) . length;
}
If you are writing in an ES6 environment, then using array comprehensions
function countBs(str) {
return [for (c of str) if (isB(c)) c] . length;
}
Try wrapping it in curly braces:
if (string.charAt(n) == "B")
{ n += 1;
i++;
}
An else requires a previous if, and no other statements in between. i++ was outside the if.
Here's my answer
function countBs(Str)
{
let char = "B" ;
return String(Str).split(char).length - 1;
}
function countChar(Str, char)
{
return String(Str).split(char).length - 1;
}

undefined is returned in JavaScript function

When I call this function, sending for example: abc as the parameter,
the function returns: undefinedcba. I can't figure out why it's adding
'undefined' to my returned value. I'm probably overlooking something obvious
but I can't spot it. Thank you.
function FirstReverse(str) {
var str_arr1 = new Array();
var ans = '';
for(i=0; i < str.length; i++) {
str_arr1.push(str.charAt(i));
}
for(j=str.length; j >= 0; j--) {
ans += str_arr1[j];
}
return ans;
}
Strings are 0-indexed. str[str.length] does not exist.
j needs to start at str.length - 1.
Or, just return str_arr1.join();
The index of the string starts at 0, so string.length is always one number bigger than index of the last character in the string.
In the second for loop, use
for(var j=str.length -1; j >= 0; j--) {
The error is in the second for statement. See the solution:
function FirstReverse(str) {
var str_arr1 = new Array();
var ans = '';
for(i=0; i < str.length; i++) {
str_arr1.push(str.charAt(i));
}
for(j=str.length-1; j >= 0; j--) {
ans += str_arr1[j];
}
return ans;
}
Because when you pass 'abc' there are only 3 characters in it.
So arrray str_arr have elements at index 0, 1 and 2.
But you are looping for str.length i.e. for 3 times and str_arr[3] is not defined.
You should do this,
function FirstReverse(str) {
var str_arr1 = new Array();
var ans = '';
for(i=0; i < str.length; i++) {
str_arr1.push(str.charAt(i));
}
for(j=str.length-1; j >= 0; j--) {
ans += str_arr1[j];
}
return ans;
}
Looks like you want to reverse a string, which you can do in this javascript one liner
function reverse(s){
return s.split("").reverse().join("");
}
The reason you are getting an undefined is because your j starts with str.length, whereas it should be str.length-1. str_arr1[str.length] is out of bounds and therefore will be undefined.

Categories