Counting occurances of character in strings - javascript

I made a function that counts the occurances of x's and o's in a given string and returns true if they are equal.
function ExOh(str) {
var x_count = 0;
var o_count = 0;
for (var i = 0;i < str.length-1;i++){
if (str[i] === 'x'){
x_count = x_count + 1;
}
else if (str[i] === 'o'){
o_count = o_count + 1;
}
}
console.log(o_count);
console.log(x_count);
if (x_count === o_count){
return true;}
else{
return false;
}
}
// keep this function call here
// to see how to enter arguments in JavaScript scroll down
ExOh(readline());
I added the lines of code
console.log(o_count);
console.log(x_count);
To see if it was counting correctly and I discovered that was the issue. After testing it I realized that this function is not testing the last element in the string. I tried changing the length of the for loop, but I can't think of what else could be wrong.
Any advice?
Thanks mates

JavaScript arrays are 0 index based objects. So, your loop should be like this
for (var i = 0; i < str.length; i++) {
otherwise the last element will be skipped.
Consider that the length of the string is 5. So, i starts from 0 and if you had your original condition
for (var i = 0; i < str.length - 1; i++) {
following are the comparisons happening in the loop
0 < 4
1 < 4
2 < 4
3 < 4
4 < 4 -- Fails
So it breaks out of the loop. But the last element will be at index 4. But when you have the condition like this
for (var i = 0; i < str.length; i++) {
the comparisons go like this
0 < 5
1 < 5
2 < 5
3 < 5
4 < 5
5 < 5 -- Fails
It breaks out of the loop only after comparing all the elements.
So, your actual program can be written like this
function ExOh(str) {
var x_count = 0, o_count = 0;
for (var i = 0; i < str.length; i++) {
if (str[i] === 'x') {
x_count = x_count + 1;
} else if (str[i] === 'o') {
o_count = o_count + 1;
}
}
return x_count === o_count;
}

alternate method to count characters:
var s = 'example';
s.split('').filter(function (i) { return i === 'e'; }).length; // 2

Your for loop is running one too short. Try this instead.
for (var i = 0;i < str.length;i++){
if (str[i] === 'x'){
x_count = x_count + 1;
}
else if (str[i] === 'o'){
o_count = o_count + 1;
}
}

Your problem is in for loop. Try changing to this.
for (var i = 0; i < str.length; i++) {
If you want to avoid using for loops, you can use this much shorter version of ExOh function.
function ExOh(str) {
return str.match(/o/g).length == str.match(/x/g).length
}

Rather than looping over the whole String with for, I'd see if using indexOf achieves a faster result
function countOccurance(haystack, needle) {
var total = 0, pos = -1;
while (-1 !== (pos = haystack.indexOf(needle, pos + 1)))
total += 1;
return total;
}
Then
var x_count = countOccurance(str, 'x'),
o_count = countOccurance(str, 'o');
return x_count === o_count;
EDIT looks like I might have been wrong about it being faster! jsperf
function indexOfMethod(haystack, needle) {
var total = 0, pos = -1;
while (-1 !== (pos = haystack.indexOf(needle, pos + 1)))
total += 1;
return total;
}
function splitMethod(haystack, needle) {
return haystack.split(needle).length - 1;
}
function forMethod(haystack, needle) {
var total = 0, i;
for (i = 0; i < haystack.length; ++i)
if (haystack.charAt(i) === needle)
total += 1;
return total;
}
The forMethod will only work with char needle, whereas the other two should work with any String as needle, if that matters.

Related

How do i return the result of all loops in javascript?

I am trying to insert dashes ('-') between each two odd numbers and insert asterisks ('*') between each two even numbers, but I am only getting the last result.
I want to print out all the elements in the array.
For example: if num is 4546793 the output should be 454*67-9-3. I Did not count zero as an odd or even number.
function StringChallenge(num) {
let result = "";
for (let i = 0; i < num.length; i++) {
if (num[i] === 0) {
continue;
}
if (num[i - 1] % 2 == 0 && num[i] % 2 == 0) {
result = num[i - 1] + "*" + num[i];
continue;
}
if (num[i - 1] % 2 == !0 && num[i] % 2 == !0) {
result = num[i - 1] + "-" + num[i];
continue;
}
}
return result;
}
console.log(StringChallenge([4,5,4,6,7,9,3]));
You do not need to check as if&continue. Inserting given numbers to the result string and only adding "-" when index and previous are odd, and "*" when index and previous are even.
function StringChallenge(num) {
let result = "";
for (let i = 0; i < num.length; i++) {
if (num[i]%2 ===0) {// even
if(i !== 0 && num[i-1]%2===0){// previous is even either
result+="*"+num[i];
}else{
result+=num[i];
}
}else{// odd
if(i !== 0 && num[i-1]%2===1){// previous is odd either
result+="-"+num[i];
}else{
result+=num[i];
}
}
}
return result;
}
console.log(StringChallenge([4,5,4,6,7,9,3]));
Try this :)
function test(a){
let result=""
for(let i=0; i < a.length; i++){
if(a[i] != 0 && a[i-1] % 2 == 0 && a[i] % 2 == 0){
result = result + '*' + a[i]
}
else if (a[i] != 0 && a[i-1] % 2 != 0 && a[i] % 2 != 0){
result = result + '-' + a[i]
}
else{
result = result + a[i]
}
}
return result
}
console.log(test([4,5,4,6,7,9,3]));
As everyone has identified, the problem is you are not adding to result.
But here is a suggestion to make your code easier to read
// These one line functions make your code easier to read
function IsEven(num){
return num % 2 === 0;
}
function IsOdd(num){
return num % 2 !== 0;
}
function StringChallenge(numArray) {
// return empty string if not an array or empty array
if(!Array.isArray(numArray) || numArray.length === 0) return "";
let result = "" + numArray[0]; // use "" to coerce first element of numArray from number to string
for (let i = 1; i < numArray.length; i++) {
// focus on the conditions to determine the separator you want between each element
separator = "";
if (numArray[i] !== 0) {
if (IsEven(numArray[i]) && IsEven(numArray[i - 1])) {
separator = "*";
} else if (IsOdd(numArray[i]) && IsOdd(numArray[i - 1])){
separator = "-";
}
}
// build the result
result += separator + numArray[i];
}
return result;
}
I will do that this way :
== some advices for 2 cents ==
1 - try to make your code as readable as possible.
2 - use boolean tests rather than calculations to simply do a parity test
3 - ES7 has greatly improved the writing of JS code, so take advantage of it
console.log(StringChallenge([4,5,4,6,7,9,3])); // 454*67-9-3
function StringChallenge( Nums = [] )
{
const
isOdd = x => !!(x & 1) // Boolean test on binary value
, isEven = x => !(x & 1) && x!==0 // zero is not accepted as Even value
;
let result = `${Nums[0]??''}`; // get first number as
// result if Nums.length > 0
for (let i=1; i<Nums.length; i++)
{
if ( isOdd(Nums[i-1]) && isOdd(Nums[i]) ) result += '-';
if ( isEven(Nums[i-1]) && isEven(Nums[i]) ) result += '*';
result += `${Nums[i]}`; // same as Nums[i].toString(10);
}
return result
}
I hope this helps. I tried to keep it as simple as possible.
function StringChallenge(num) {
//start with a string to concatenate, or else interpreter tries to do math
operations
let result = num[0].toString();
function checkOdd(num){ //helper function to check if odd
return num % 2
}
for (let i = 0; i < num.length - 1; i++) {
if (checkOdd(num[i]) && checkOdd(num[i+1])) { //checks if both odd
result += `-${num[i+1]}`; //adds - and next number
} else if (!checkOdd(num[i]) && !checkOdd(num[i+1])) { //checks if both even
result += `*${num[i+1]}`; //adds * and next number
} else { //otherwise
result += num[i+1]; //just add next number
}
}
return result;
}
console.log(StringChallenge([4,5,4,6,7,9,3]));
Use +=. And, change your logic, your code prints out "4*67-99-3".
The zero check was pretty hard for me I hope the variables in my code explain itself. If not, let me know.
function even(num) {
return num % 2 === 0;
}
function odd(num) {
return num % 2 !== 0;
}
function StringChallenge(num) {
let result = "";
for (let i = 0; i < num.length; i++) {
var currentZero = num[i] === 0
var previousZero = num[i-1] === 0
var bothEven = even(num[i]) && even(num[i-1])
var bothOdd = odd(num[i]) && odd(num[i-1])
var firstNumber = (i === 0)
if (!currentZero) {
if (firstNumber) {
result += num[i]
} else {
if (bothEven && !previousZero) {
result += "*" + num[i]
} else if (bothOdd && !currentZero) {
result += "-" + num[i]
} else {
result += num[i]
}
}
}
}
return result;
}
console.log(StringChallenge([0,4,5,0,4,6,7,9,3]));

for loops with and without block statements

I looked for a function to determine if a number is prime and found this
for (var i = 2; i <= Math.sqrt(num); i++)
if (num % i === 0) {
return false;
}
return true;
and I don't understand why that works, yet this doesn't
for (var i = 2; i <= Math.sqrt(num); i++) {
if (num % i === 0) {
return false;
}
return true;
}
What is it about the (lack of the) block statement that is functioning differently
Your first code looks like this:
for (var i = 2; i <= Math.sqrt(num); i++){
if (num % i === 0) {
return false;
}
}
return true;
Notice how return true is on the outside. Your second code doesn't work because it prematurely returns true when there are more numbers to check. Your entire for loop is equivalent to
return num % 2 !== 0;
which is clearly incorrect.
Let me tell you something about blocks that you might not have known (It took me a while to discover this at least).
When you use a loop or if-else statement, you can ignore the using braces { and }.
Example 1
if (a === b){
c = 0;
}
is actually the same as
if (a === b)
c = 0;
Example 2
for (i = 0; i < 10; i++){
a += 1;
}
is actually the same as
for (i = 0; i < 10; i++)
a += 1;
However 1
if (a === b){
c = 0;
d = 1;
}
is not the same with
if (a === b)
c = 0;
d = 1;
However 2
for (i = 0; i < 10; i++){
a += 1;
b += 1;
}
is not the same with
for (i = 0; i < 10; i++)
a += 1;
b += 1;
Explanation
In loops and if-else statement, the block statement (codes surrounded by { and } groups the codes within it and execute it.
However, in the absence of { and }, the loops or if-else statement will only execute the single line of code after it.
Meaning,
var a = 0,
b = 0;
for (i = 0; i < 10; i++)
a += 1;
b += 1;
In this case, a === 10 but b === 1.
Also, in the following case,
var a = 0,
b = 0;
if (false)
a = 10;
b = 10;
a === 0 but b === 10.

How do you iterate over an array every x spots and replace with letter?

/Write a function called weave that accepts an input string and number. The function should return the string with every xth character replaced with an 'x'./
function weave(word,numSkip) {
let myString = word.split("");
numSkip -= 1;
for(let i = 0; i < myString.length; i++)
{
numSkip += numSkip;
myString[numSkip] = "x";
}
let newString = myString.join();
console.log(newString);
}
weave("weave",2);
I keep getting an infinite loop. I believe the answer I am looking for is "wxaxe".
Here's another solution, incrementing the for loop by the numToSkip parameter.
function weave(word, numToSkip) {
let letters = word.split("");
for (let i=numToSkip - 1; i < letters.length; i = i + numToSkip) {
letters[i] = "x"
}
return letters.join("");
}
Well you need to test each loop to check if it's a skip or not. Something as simple as the following will do:
function weave(word,numSkip) {
var arr = word.split("");
for(var i = 0; i < arr.length; i++)
{
if((i+1) % numSkip == 0) {
arr[i] = "x";
}
}
return arr.join("");
}
Here is a working example
Alternatively, you could use the map function:
function weave(word, numSkip) {
var arr = word.split("");
arr = arr.map(function(letter, index) {
return (index + 1) % numSkip ? letter : 'x';
});
return arr.join("");
}
Here is a working example
Here is a more re-usable function that allows specifying the character used for substitution:
function weave(input, skip, substitute) {
return input.split("").map(function(letter, index) {
return (index + 1) % skip ? letter : substitute;
}).join("");
}
Called like:
var result = weave('weave', 2, 'x');
Here is a working example
You dont need an array, string concatenation will do it, as well as the modulo operator:
function weave(str,x){
var result = "";
for(var i = 0; i < str.length; i++){
result += (i && (i+1)%x === 0)?"x":str[i];
}
return result;
}
With arrays:
const weave = (str,x) => str.split("").map((c,i)=>(i&&!((i+1)%x))?"x":c).join("");
You're getting your word greater in your loop every time, so your loop is infinite.
Try something like this :
for(let k = 1; k <= myString.length; k++)
{
if(k % numSkip == 0){
myString[k-1]='x';
}
}
Looking at what you have, I believe the reason you are getting an error is because the way you update numSkip, it eventually becomes larger than
myString.length. In my code snippet, I make i increment by numSkip which prevents the loop from ever executing when i is greater than myString.length. Please feel free to ask questions, and I will do my best to clarify!
JSFiddle of my solution (view the developer console to see the output.
function weave(word,numSkip) {
let myString = word.split("");
for(let i = numSkip - 1; i < myString.length; i += numSkip)
{
myString[i] = "x";
}
let newString = myString.join();
console.log(newString);
}
weave("weave",2);
Strings are immutable, you need a new string for the result and concat the actual character or the replacement.
function weave(word, numSkip) {
var i, result = '';
for (i = 0; i < word.length; i++) {
result += (i + 1) % numSkip ? word[i] : 'x';
}
return result;
}
console.log(weave("weave", 2));
console.log(weave("abcd efgh ijkl m", 5));
You can do this with fewer lines of code:
function weave(word, numSkip) {
word = word.split("");
for (i = 0; i < word.length; i++) {
word[i] = ((i + 1) % numSkip == 0) ? "x" : word[i];
}
return word.join("");
}
var result = weave("weave", 2);
console.log(result);

- I am trying to write a code where input should be abbbcc and output should be a1b3c2

I am new to js.
I am trying to write a code where input should be abbbcc and output should be a1b3c2.
not sure how to get it
providing code below
var word = "abbbcc";
var countword = [];
for (i=0; i < word.length; i++) {
if (word[i] === charAt && word[i] != word[i+1]) {
countword.push(word[i]);
countword.push(i++);
}
else (word[i] === charAt && word[i] != word[i+1]) {
countword.push(word[i]);
for (i=0; i < word.length; i++) {
if (word[i+1] === word[i+2]) {
countword.push(i++);
}
else{
break;
}
}
}
}
console.log("result----->" + countword);
It can be done using a for loop and a counter like this.
var word = "abbbcc";
var countword = "";
var counter = 1;
for (i=0; i < word.length; i++) {
if ( word[i] != word[i+1]) {
// Save the letter and the counter
countword += word[i]+counter;
// Reset the counter
counter=1;
}else{
// Increment counter
counter++;
}
}
console.log("result-----> " + countword );
Alternative solution using Array#reduce. I've described each step, I hope you will get my point and understand how does it works.
var word = "abbbcc".split(''),
res = '',
counter = 1;
word.reduce(function(s, a, i, r) {
if (s !== a) { //if the succeeding element doesn't match the previous one
res += s + counter; //concat it to the string + the amount of appearances (counter)
counter = 1; //reset the counter
} else {
counter++; //the succeeding element matches the previous one, increment the counter
}
if (i === r.length - 1 && counter > 0) { //if the loop is over
res += s + counter; //add the last element
}
return a;
})
console.log(res);

Insert dashes into a number

Any ideas on the following? I want to input a number into a function and insert dashes "-" between the odd digits. So 4567897 would become "456789-7". What I have so far is to convert the number into a string and then an array, then look for two odd numbers in a row and use the .splice() method to add the dashes where appropriate. It does not work and I figure I may not be on the right track anyway, and that there has to be a simpler solution.
function DashInsert(num) {
var numArr = num.toString().split('');
for (var i = 0; i < numArr.length; i++){
if (numArr[i]%2 != 0){
if (numArr[i+1]%2 != 0) {
numArr.splice(i, 0, "-");
}
}
}
return numArr;
}
The problem is you're changing the thing you're iterating over. If instead you maintain a separate output and input...
function insertDashes(num) {
var inStr = String(num);
var outStr = inStr[0], ii;
for (ii = 1; ii < inStr.length; ii++) {
if (inStr[ii-1] % 2 !== 0 && inStr[ii] % 2 !== 0) {
outStr += '-';
}
outStr += inStr[ii];
}
return outStr;
}
You can try using regular expressions
'4567897'.replace(/([13579])(?=[13579])/g, '$1-')
Regex Explained
So, we find an odd number (([13579]) is a capturing group meaning we can use it as a reference in the replacement $1) ensure that it is followed by another odd number in the non-capturing positive lookahead ((?=[13579])) and replace the matched odd number adding the - prefix
Here is the function to do it:
function dashes(number){
var numString = '';
var numArr = number.toString().split('');
console.log(numArr);
for(i = 0; i < numArr.length; i++){
if(numArr[i] % 2 === 1 && numArr[i+1] % 2 === 1){
numString += numArr[i] + '-';
}else{
numString += numArr[i];
}
}
console.log(numString);
}
dashes(456379);
Tested and everything.
Edit: OrangeDog's answer was posted earlier (by nearly a full half hour), I just wanted to make an answer which uses your code since you're almost there.
Using another array instead of splicing into one you were looping through (this happens to return a string using join):
var num = 4567897;
function DashInsert(num) {
var numArr = num.toString().split('');
var len = numArr.length;
var final = [];
for (var i = 0; i < len; i++){
final.push(numArr[i]);
if (numArr[i]%2 != 0){
if (i+1 < len && numArr[i+1]%2 != 0) {
final.push("-")
}
}
}
return final.join("");
}
alert(DashInsert(num));
function dashInsert(str) {
var arrayNumbers = str.split("");
var newString = "";
for (var i = 0; i < arrayNumbers.length; i++){
if(arrayNumbers[i] % 2 === 1 && arrayNumbers[i + 1] % 2 === 1){
newString = newString + arrayNumbers[i] + "-";
} else {
newString = newString + arrayNumbers[i];
}
}
return newString;
}
var result = dashInsert("3453246");
console.log(result);

Categories

Resources