Counting the occurrence of chars in a javascript string - javascript

I have written down code to calculate the count of each of the character in a string.
It seems to be working correctly for some of the words where as for some it fails.
It fails for the last character, as I see the length of the string becomes smaller than the iteration count (but for some of the words)
var str1 = "america"
function noofchars(str1) {
for (var m = 0; m < str1.length + 1; m++) {
var countno = 1;
if (m != 0) {
str1 = str1.slice(1)
}
str2 = str1.substr(0, 1)
for (var i = 0; i < str1.length; i++) {
if (str2 === str1.charAt(i + 1)) {
countno += 1
str1 = str1.slice(0, i + 1) + str1.slice(i + 2) + " "
}
}
console.log(str1.charAt(0) + "=" + countno)
}
}
var findnoofchar = noofchars(str1)
It passes for london, philadelphia, sears, happy
But fails for america, chicago etc
london = l=1, o=2, n=2, d=1

It'd be easier to use an object. First reduce into character counts, then iterate through the key/value pairs and console.log:
function noofchars(str1) {
let r = [...str1].reduce((a, c) => (a[c] = (a[c] || 0) + 1, a), {});
Object.entries(r).forEach(([k, v]) => console.log(`${k}=${v}`));
}
noofchars("america");
ES5 syntax:
function noofchars(str1) {
var r = str1.split("").reduce(function(a, c) {
a[c] = (a[c] || 0) + 1;
return a;
}, {});
Object.keys(r).forEach(function(k) {
console.log(k + "=" + r[k]);
});
}
noofchars("america");
It's easier to understand what reduce is doing in the above snippet.
First, we take a function with two parameters a and c. These can be called anything, I just use a and c for the accumulator and the current item.
Now, the second line:
a[c] = (a[c] || 0) + 1;
This is kind hard, so let's break it down. First let's look at what's in the parentheses:
a[c] || 0
This checks if a has a key/value pair with the key c (as in, the value of c, not the key literally being c). If that doesn't exist, it returns 0. So if a[c] exists, save it as the value of the expression, otherwise use 0.
Now, we add 1, to increment the value.
Finally, we assign the result to a[c]. So if a contained c, the value of a[c] would be incremented. If a didn't contain c, the value of a[c] would be 1.
Then, we return a to be used in the next iteration of reduce.
In the next line:
}, {});
We assign a default value for a. If we didn't do this, the first time reduce ran, a would be "a", and c would be "m" (the first two characters of america). This way, a is {} (an empty object), and c is "a". If we didn't have this second argument, our function wouldn't work.
In this line:
Object.keys(r).forEach(function(k) {...});
We're getting an array of all the keys in r, and looping through them with forEach, with k being the key.
Then, we're logging k (the key), then an equals sign =, then the value of r[k].

You can split the string by each character and then count the number of occurrence of each character by reduce function as below
function noofchars(str1) {
const chArray = str1.split('');
return chArray.reduce(function(acc, ch) {
if (acc[ch]) {
acc[ch]++;
} else {
acc[ch] = 1;
}
return acc;
}, {});
}
var str1 = "america";
var findnoofchar = noofchars(str1);
console.log(findnoofchar);
In your solution you are mutating str1 in this line
str1 = str1.slice(0, i + 1) + str1.slice(i + 2) + " "
which actually changes the length of the string and also checking str1.length in the first loop. In you case you can take the length in the first place. Working version of your code snippet is here
var str1 = "america"
function noofchars(str1) {
const len = str1.length;
for (var m = 0; m < len; m++) {
var countno = 1;
if (m !== 0) {
str1 = str1.slice(1)
}
if (str1.charAt(0) === ' ') {
break;
}
str2 = str1.substr(0, 1)
for (var i = 0; i < str1.length; i++) {
if (str2 === str1.charAt(i + 1)) {
countno += 1
str1 = str1.slice(0, i + 1) + str1.slice(i + 2) + " "
}
}
console.log(str1.charAt(0) + "=" + countno)
}
}
var findnoofchar = noofchars(str1)

Not really knowing what you are trying to accomplish with your code, one solution is to utilize the charAt and Set functions. CharAt is a more direct way to iterate over the string and the Set function eliminates duplicate characters from the set automatically.
var str1 = "america";
function noofchars(str1) {
var charList = new Set();
for (var m = 0; m < str1.length; m++) {
var charX = str1.charAt(m).substr(0, 1);
var countno = 1;
for (var i = 0; i < str1.length; i++) {
if (str1.slice(0, i + 1) == charX) {
countno++;
}
charList.add(charX + "=" + countno);
}
}
// you may need to expand set on Chrome console
console.log(charList);
// a hack to display more easily display on your screen
var listOnScreen = Array.from(charList);
document.getElementById('displaySet').innerHTML=listOnScreen;
}
noofchars(str1);
<div id="displaySet"></div>

Related

How to combine 2 strings from an array if their length is shorter then x

I am trying to combine words like "my", "I", "for" etc, with their neighbor word.
I was thinking that I may check each word's length and if it's shorter than 4 for example, join them with the next word.
Let's say I have the string 'about my projects':
What I did was split it into a separate words like this
const words = string.split(" ");
Once I had the words I looped through them like this
for (let i = 0; i <= words.length; i++) {
if (words[1 + i].length <= 3) {
const joinedWords = words[1] + " " + words[1 + i];
formattedWords.push(joinedWords);
}
}
The reason I used [1 + i] is that I wanted the first word of the string to always be a separate word.
Unfortunately trying this does not work and the console throws an error: Uncaught TypeError: Cannot read properties of undefined (reading 'length')
Is there a way I could join words that are shorter than 4 characters with the next word like this?
input ['about', 'my', 'projects'];
output ['about', 'my projects'];
input ['something','for','something','for'];
output ['something'.'for something'.'for'];
function joinWords(inp) {
const res = []
const arr = inp.split(' ')
res.push(arr[0])
let skipNext = false
for (let i=1; i<=arr.length-1; i++) {
if(skipNext) {
skipNext = true
continue
}
if (i < arr.length-1 && arr[i].length <= 3) {
const joined = arr[i] + " " + arr[i + 1]
res.push(joined)
skipNext = true
} else {
res.push(arr[i])
}
}
return res
}
console.log(joinWords('about my projects'))
console.log(joinWords('something for something for'))
With for loop and continue to skip the iteration when matched condition
function combine(data){
const res = [];
let temp;
for (let i = 0; i < data.length; i++) {
if (i === temp) continue;
if (data[i].length < 4 && i !== data.length - 1) {
res.push(data[i] + " " + data[i + 1]);
temp = i + 1;
} else {
res.push(data[i]);
}
}
return res;
}
console.log(combine(["about", "my", "projects"]));
console.log(combine(['something','for','something','for']));
In this version I will continue to concatenate words, as long as they are shorter than 4 characters:
const wrds=['about','a','b','c','and','my', 'projects','and','other','hot','and','great','things'];
console.log(wrds.reduce((a,c,i,arr)=>{
if (a.last) {
a.last=a.last+' '+c;
if (c.length>3){
a.push(a.last);
a.last=null;
}
}
else if(c.length>3||i==arr.length-1){
a.push(c);
}
else a.last=c;
return a;
},[]));

JavaScript bug: function returns NaN even though typeof function returns "number"

I want to find the largest number resulted from the permutations of a given number.
If the given number is 123, the largest number resulted from the permutations of it is 321.
EDIT
I have done some progress by changing
if (str.length === 0) return "";
if (str.length === 1) return str;
to
if (str.length === 0) {
return "";
} else {
return str;
}
A problem remains, however: the function returns a string. In fact, the array members are strings instead of numbers.
function findPerms(num) {
var str = num.toString();
if (str.length === 0) {
return "";
} else {
return str;
}
let result = [];
for (let i = 0; i < str.length; i++) {
const currentChar = str[i];
const remainingChars = str.slice(0, i) + str.slice(i + 1);
for (let j = 0; j < remainingChars.length; j++) {
result.push(Number(currentChar + findPerms(remainingChars)[j]));
}
}
result.sort(function(a, b) {
return a - b;
});
return result[result.length - 1];
}
console.log(findPerms(11121));
console.log(typeof findPerms(11121));
For this purpose I did:
function findPerms(num) {
var str = num.toString();
if (str.length === 0) return "";
if (str.length === 1) return str;
let result = [];
for (let i = 0; i < str.length; i++) {
const currentChar = str[i];
const remainingChars = str.slice(0, i) + str.slice(i + 1);
for (let j = 0; j < remainingChars.length; j++) {
result.push(Number(currentChar + findPerms(remainingChars)[j]));
}
}
result.sort(function(a, b) {
return a - b;
});
return result[result.length - 1];
}
console.log(findPerms(11121));
console.log(typeof findPerms(11121));
The problem
I must have made a mistake I was unable to spot because the function above returns NaN (even though typeof findPerms(11121) returns "number").
Where is my mistake?
There are a couple of issues with your code, but let's try to define the requirements correctly first.
If I understand what you want to do is to find all permutations of a number and select the highest possible permutation of the digits in the number.
What you are trying to do is something like this:
Create an empty list
Loop through the digits of the initial number.
For each digit loop trough the remaining digits and find all possible combinations left and add them to the initial empty list.
After you have all possible combinations of numbers in the list sort them and return the highest result.
There are 2 problems here, first there are some mistakes in the execution of the code and your algorithm is not very efficient.
Let's tackle the first one:
When you create the result list you define it inside the recursive function, this means that it will be overwritten with an empty array on each recursive call. Usually when you apply this technique you either define the result array outside of the recursive function or you pass it as a argument in order to be able to iterate over the result.
You seem to not have a good grasp of how function scope and how closures work in JS. I would advise reading some resources on MDN for this.
Another problem here is that you expect the function to receive a number as argument, but when you call it in
result.push(Number(currentChar + findPerms(remainingChars)
remainingChars is a string, hence the NaN result.
Now on to the second problem. Considering that you want the highest possible number from a series of digits you could just sort the digits from highest to smallest and just provide the result.
EG:
If the number is 18, you can sort it in array like [8, 1] and then concatenate it to 81.
The code would probably look smth like:
function findHighestPerm(no) {
const arr = no.toString().split('');
return parseInt(arr.sort((a, b) => b - a).join(''));
}
PS: I am aware that my code is not the most efficient or elegant, but I am just lazy and it works ;)
Edit
I think this is what you would like to do.
Make an array of all digit permutations of a number using recursion.
Sort the array.
Return the permutation with the largest number.
This can be done by breaking the problem it into two functions.
The first function returns an array of all permutations of a number.
The second function takes an array result from the first function then sorts it. Then it returns the last value.
Your recursion was not operating properly. That is why it didn't work.
<html><head><title>6770990</title>
<script>
function findPerms(num) {
var str = num.toString(); var result = [];
if (str.length == 0) return result;
if (str.length == 1) return [parseInt(str)];
for (var i = 0; i < str.length; i++) {
const currentChar = str[i];
const remainingChars = str.slice(0, i) + str.slice(i + 1)
var perms = findPerms(remainingChars) //----Permutation array of remaining chars.
for (var j = 0; j < perms.length; j++) {
result.push(parseInt("" + currentChar + perms[j]));
}
}
return result; //----All permutations for num.
}
function findLargestPerm(num)
{ var perms = findPerms(num); perms.sort(function(a,b) {return a-b;});
return perms[perms.length-1];
}
</script>
</head></body>
<script>
var r = findLargestPerm(11121); alert("r=" + r);
</script>
</body></html>
Previous answer
It would be more efficient to just sort the digits in reverse order and concatenate into a number. This would be the largest permutation.
The function findPerms() is trying to find the largest permutation of a set of digits. Sometimes it helps to rename a function to what it does, so that it is easier to follow the logic.
The line that calls the function using recursion again only needs to be called once for each current character.
The following code shows the steps that happen.
<html><head><title>6770990</title>
<script>
var msg="";
function findLargestPermutation(num)
{ var str = num.toString(); msg += "findLargestPermutation(" + str + ")<br>";
if (str.length === 0) return "";
if (str.length === 1) return str;
let result = [];
for (let i = 0; i < str.length; i++)
{ const currentChar = str[i];
const remainingChars = str.slice(0, i) + str.slice(i + 1);
msg += "currentChar=" + currentChar + " remainingChars=" + remainingChars + "<br>";
//----The j loop should be removed and just use this line.
var num = Number(currentChar + findLargestPermutation(remainingChars));
msg += "num=" + num + "<br>";
result.push(num);
}
result.sort(function(a, b) {return a - b;});
msg += "findLargestPermutation()=" + result[result.length - 1] + "<br>";
return result[result.length - 1];
}
</script>
</head><body>
<div id="div"></div>
<script>
var lp = findLargestPermutation(11121);
alert("lp=" + lp + " typeof lp=" + typeof lp);
document.getElementById("div").innerHTML = msg;
</script>
</body></html>

decodeString codefights: Program doesn't pass all tests."30/31 Output limit exceeded on test -31". Kindly support

function decodeString(s)
{
let arr = [];
let digitSum = '';
let digitSumArr = []; // for numbers before '['
let i;
//iterating string
for (i = 0; i < s.length; i++)
{
if (!isNaN(s[i]))
{
digitSum += s[i]; // count number before '['
}
else if (s[i] === '[')
{
// add number to the array
digitSumArr.push(+digitSum);
arr.push(i + 1);
digitSum = '';
}
else if (s[i] === ']')
{
let digit = digitSumArr.pop();
i = decStr(arr, i, digit);
digitSum = '';
}
else
{
digitSum = '';
}
}
return s;
function decStr(arr, j, number)
{
let arrLen = arr.length;
let n = number;
let str = s.slice(arr[arrLen - 1], j);
let sumStr = str;
while (n-- > 1)
{
sumStr = sumStr.concat(str);
}
str = number + '[' + str + ']';
s = s.replace(str, sumStr);
arr.splice(arrLen - 1, 1);
//return position for iterating
return j + sumStr.length - str.length - 1;
}
}
Given an encoded string, return its corresponding decoded string.
The encoding rule is: k[encoded_string], where the encoded_string inside the square brackets is repeated exactly k times.
Note: k is guaranteed to be a positive integer.
Note that your solution should have linear complexity because this is what you will be asked during an interview.
The problem is that the failed test has an input of sufficient complexity to require more time to solve than the allotted limit, given your solution. So, you need to find a more efficient solution.
I ran a performance benchmark on your solution and on another solution which used recursive procedure calls, and yours was 33% slower. I suggest you refactor your solution to call your parsing procedure recursively when you encounter nested iterations.

how to increment the value of a char in Javascript

How do I increment a string "A" to get "B" in Javascript?
function incrementChar(c)
{
}
You could try
var yourChar = 'A'
var newChar = String.fromCharCode(yourChar.charCodeAt(0) + 1) // 'B'
So, in a function:
function incrementChar(c) {
return String.fromCharCode(c.charCodeAt(0) + 1)
}
Note that this goes in ASCII order, for example 'Z' -> '['. If you want Z to go back to A, try something slightly more complicated:
var alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('')
function incrementChar(c) {
var index = alphabet.indexOf(c)
if (index == -1) return -1 // or whatever error value you want
return alphabet[index + 1 % alphabet.length]
}
var incrementString = function(string, count){
var newString = [];
for(var i = 0; i < string.length; i++){
newString[i] = String.fromCharCode(string[i].charCodeAt() + count);
}
newString = newString.join('');
console.log(newString);
return newString;
}
this function also can help you if you have a loop to go through

How to parse a string for having line breaking

I would like to have a function which takes 3 arguments:
sentence (string),
maxCharLen=20 (number),
separator (string)
and transform the sentence based on the parameters.
Example
var sentence = "JavaScript is a prototype-based scripting language that is dynamic, weakly typed and has first-class functions."
var newSentence = breakSentence(sentence, maxCharLen=20, separator="<br>");
newSentence // JavaScript is a prototype-based <br> scripting language that is dynamic, <br> weakly typed and has first-class functions.
P.S:
This is what I have tried:
var breakSentence = function (sentence, maxCharLen, separator)
{
sentence = sentence || "javascript is a language" ;
maxCharLen = 10 || maxCharLen; // max numb of chars for line
separator = "<br>" || separator;
var offset;
var nbBreak = sentence.length // maxCharLen;
var newSentence = "";
for (var c = 0; c < nbBreak; c += 1)
{
offset = c * maxCharLen;
newSentence += sentence.substring(offset, offset + maxCharLen) + separator;
}
return newSentence;
}
It works in this way:
breakSentence() // "javascript<br> is a lang<br>uage<br>"
it should be:
breakSentence() // "javascript<br>is a <br>language"
Here's a solution: http://snippets.dzone.com/posts/show/869
//+ Jonas Raoni Soares Silva
//# http://jsfromhell.com/string/wordwrap [v1.0]
String.prototype.wordWrap = function(m, b, c){
var i, j, l, s, r;
if(m < 1)
return this;
for(i = -1, l = (r = this.split("\n")).length; ++i < l; r[i] += s)
for(s = r[i], r[i] = ""; s.length > m; r[i] += s.slice(0, j) + ((s = s.slice(j)).length ? b : ""))
j = c == 2 || (j = s.slice(0, m + 1).match(/\S*(\s)?$/))[1] ? m : j.input.length - j[0].length
|| c == 1 && m || j.input.length + (j = s.slice(m).match(/^\S*/)).input.length;
return r.join("\n");
};
usage:
var sentence = "JavaScript is a prototype-based scripting language that is dynamic, weakly typed and has first-class functions."
sentence.wordWrap(20, "<br>",true)
// Output "JavaScript is a <br>prototype-based <br>scripting language <br>that is dynamic, <br>weakly typed and has<br> first-class <br>functions."
I would try it like that (not tested):
var breakSentence = function (sentence, maxCharLen, separator)
{
var result = "";
var index = 0;
while (sentence.length - index > maxCharLen)
{
var spaceIndex = sentence.substring(index, index + maxCharLen).lastIndexOf(' ');
if (spaceIndex < 0) //no spaces
{
alert('Don\'t know what do do with substring with one long word');
spaceIndex = maxCharLen; //assume you want to break anyway to avoid infinite loop
}
result += sentence.substring(index, index + spaceIndex + 1) + separator;
index += spaceIndex + 1;
}
return result;
}
Should break after spaces only now...
Here is my attempt to get it. It has two things you should notice:
it first removes all the separator instances (so the reordering is completely new)
it doesn't break words longer then maxCharLen characters.
It worked in node 0.6.10
var breakSentence = function (sentence, maxCharLen, separator) {
var words = [] // array of words
, i // iterator
, len // loop
, current = '' // current line
, lines = [] // lines split
;
sentence = sentence || "javascript is a language";
maxCharLen = 10 || maxCharLen;
separator = separator || "<br>";
sentence = sentence.replace(separator, '');
if (sentence.length < maxCharLen) return [sentence]; // no need to work if we're already within limits
words = sentence.split(' ');
for (i = 0, len = words.length; i < len; i += 1) {
// lets see how we add the next word. if the current line is blank, just add it and move on.
if (current == '') {
current += words[i];
// if it's not like that, we need to see if the next word fits the current line
} else if (current.length + words[i].length <= maxCharLen) { // if the equal part takes the space into consideration
current += ' ' + words[i];
// if the next word doesn't fit, start on the next line.
} else {
lines.push(current);
current = words[i];
// have to check if this is the last word
if (i === len -1) {
lines.push(current);
}
}
}
// now assemble the result and return it.
sentence = '';
for (i = 0, len = lines.length; i < len; i += 1) {
sentence += lines[i];
// add separator if not the last line
if (i < len -1) {
sentence += separator;
}
}
return sentence;
}

Categories

Resources