Finding a first letter most repeated in an string - javascript

Good evening, I proceed to explain my situation. I started to get interested in javascript which started to dabble
in this language, I have been doing some online courses which I have encountered the following task, basically I am trying through the condition "for" tell me what is the first repeated letter of a string also adding the funsion ".UpperCase () "which at the beginning worked best, until I entered more characters to the string in this case" x "throwing me as output result" undefined "instead of" the most repeated word is: X "reach the case that the string should Consider all the letters regardless of whether they are lowercase or capital letters, for which I ask for help to understand if ¿there is another way? for this task and thus move forward (Sorry for my bad english)
Well i making this task in JavasScript with Atom Editor
var word = "SQSQSQSSaaaassssxxxY";
var contendor = [];
var calc = [];
var mycalc = 0;
function repeat() {
for (var i = 0; i < word.length; i++) {
if (contendor.includes(word[i])) {} else {
contendor.push(word[i])
calc.push(0)
}
}
for (var p = 0; p < word.length; p++) {
for (var l = 0; l < contendor.length; l++) {
if (word[p].toUpperCase() == word[l]) {
calc[l] = calc[l] + 1
}
}
}
for (var f = 0; f < calc.length; f++) {
if (calc[f] > mycalc) {
mycalc = calc[f]
}
}
}
repeat()
console.log("The first letter repeated its: " + contendor[mycalc])
I expected the output of the String to be: "X"
but the actual output is: "Undefined"

The first error in your script is that you store the wrong value in mycalc:
mycalc = calc[f]
Since you want mycalc to be an index, the above should have been
mycalc = f
Now, you will get a result, but your code is actually going through a lot of effort to find the uppercase character that is repeated most often, not first.
Your comparison should have used toUpperCase on both sides of the comparison, otherwise lower case letters will never match.
To get the character that was repeated most often, you could use a Map (to keep track of the counts like you did in calc):
function mostRepeated(str) {
const map = new Map;
let result;
let maxCount = 0;
for (let ch of str) {
ch = ch.toUpperCase();
let count = (map.get(ch) || 0) + 1;
map.set(ch, count);
if (count > maxCount) {
maxCount = count;
result = ch;
}
}
return result;
}
var word = "MBXAYMZAXmZYxxxxxxxxxxmBxAYMZaXmZY";
console.log(mostRepeated(word));
Note that you should better use function parameters and local variables. Declaring your variables as global is not considered best practice.

You could find the letter that occurs the most number of times in a string by:
first creating a map that relates each unique letter, to the number of times it occurs in the string
converting that map to an array of "key/value" entries, and then sorting those entries by the "count value"
returning the "letter key" that has the largest count
One way to express this in JavaScript would be via the following:
function findMaxLetter(word) {
/* Create a map that relates letters to the number of times that letter occours */
const letterCounts = Array.from(word).reduce((map, letter) => {
return { ...map, [letter] : (map[letter] === undefined ? 0 : map[letter] + 1) }
}, {})
/* Sort letters by the number of times they occour, as determined in letterCounts map */
const letters = Object.entries(letterCounts).sort(([letter0, count0], [letter1, count1]) => {
return count1 - count0
})
.map(([letter]) => letter)
/* Return letter that occoured the most number of times */
return letters[0]
}
console.log("The first letter repeated its: " + findMaxLetter("MBXAYMZAXmZYxxxxxxxxxxmBxAYMZaXmZY"))

I this is solution is most detailed for you
function func( word ){
word = word.toLowerCase();
var i, charCountCache = {};
//store all char counts into an object
for( i = 0; i < word.length; i++){
if( charCountCache[ word[ i ] ] )
charCountCache[ word[ i ] ] = charCountCache[ word[ i ] ] + 1;
else
charCountCache[ word[ i ] ] = 1;
}
//find the max value of char count in cached object
var fieldNames = Object.keys( charCountCache )
, fieldValues = Object.values( charCountCache )
, mostReapeatChar = '', mostReapeatCharCount = 0;
for( i = 0; i < fieldNames.length; i++ ){
if( mostReapeatCharCount < fieldValues[i] ){
mostReapeatCharCount = fieldValues[i];
mostReapeatChar = fieldNames[i];
}
}
console.log('most repeating char: ', mostReapeatChar, ' no of times: ', mostReapeatCharCount )
}

console.log("The first letter repeated its: " + contendor[mycalc])
You tried to print the 14th index of contendor which has only 9 values, that is why your log result was undefined.
You probably wanted to print word[mycalc].
Also if you intended to count x as X, you should have added toUpperCase() to every letter you process/go-through.
This is only a note to the issues in your code, there are better/faster/cleaner solutions to reach the result which i am sure other answers will provide.

my advice would be to create a hashmap such as
letter => [indexLetter1, indexLetter2].
From that hashmap, you could easily find your first repeated letters.
For that string MBXAYMZAXmZYxxxxxxxxxxmBxAYMZaXmZY, hashmap will look like
[
M => [0,5,..],
B => [1, ..],
X => [2, ..],
...
]
now you can find every letter with multiple values in its array, then in those arrays take the one with the lowest value.

If you want to get the index of most repeated letter, you can use Array.from to convert the word into an array. Add a map function to make all letters uppercase.
Get the count of each letter by using reduce and Object.entries
Use indexOf to the get the index of the lettet in the array. Please note that indexOf count the letters from 0.
var word = "MBXAYMZAXmZYxxxxxxxxxxmBxAYMZaXmZY";
var letters = Array.from(word, o => o.toUpperCase());
var [highestLetter, highestCount]= Object.entries(letters.reduce((c, v) => (c[v] = (c[v] || 0) + 1, c), {})).reduce((c, v) => c[1] > v[1] ? c : v);
var index = letters.indexOf(highestLetter);
console.log("Most repeated letter:", highestLetter);
console.log("Count:", highestCount);
console.log("First Index:", index);

Related

I'd like someone to help me understand a few lines of code. Can someone help me explain them? Thanks

I'm doing an algorithm on Codesignal.
For s = "abacabad", the output should be
firstNotRepeatingCharacter(a) = 'c'.
There are 2 non-repeating characters in the string: 'c' and 'd'. Return c since it appears in the string first.
For s = "abacabaabacaba", the output should be
firstNotRepeatingCharacter(s) = '_'.
There are no characters in this string that do not repeat.
Code below:
function firstNotRepeatingCharacter(a) {
let b = {};
let len = a.length;
for (let i = 0; i < len; i++) {
let tmp = a.charAt(i);
if (b[tmp]) {
b[tmp] += 1; //explain here
}
else {
b[tmp] = 1;
}
}
for (var prop in b) {
if (b[prop] == 1) { //explain here
return prop;
}
}
return '_';
}
Actually in the above b is an object whose keys are different letters of the string and the values of those keys are count of respective lettter in the string.
key => letter
value => Count of that letter
tmp will be character through you are iterating.
if (b[tmp]) checks whether the letter is already added to the object.
If its already there so increase the count.
Otherwise set it to one.
In the second loop if (b[prop] == 1) checks whether the count of certain letter is 1. means that it only occurred once in the string so return the letter.

How make a more concise code using the For statement?

I'm new in StackOverflow and JavaScript, I'm trying to get the first letter that repeats from a string considering both uppercase and lowercase letters and counting and obtaining results using the for statement. The problem is that the form I used is too long Analyzing the situation reaches such a point that maybe you can only use a "For" statement for this exercise, which I get to iterate, but not with a cleaner and reduced code has me completely blocked, this is the reason why I request help to understand and continue with the understanding and use of this sentence. In this case, the result was tested in a JavaScript script inside a function and 3 "For" sentences obtaining quite positive results, but I can not create it in 1 only For (Sorry for my bad english google translate)
I making in HTML with JavasScript
var letter = "SYAHSVCXCyXSssssssyBxAVMZsXhZV";
var contendor = [];
var calc = [];
var mycalc = 0;
letter = letter.toUpperCase()
console.log(letter)
function repeats(){
for (var i = 0; i < letter.length; i++) {
if (contendor.includes(letter[i])) {
}else{
contendor.push(letter[i])
calc.push(0)
}
}
for (var p = 0; p < letter.length; p++) {
for (var l = 0; l < contendor.length; l++) {
if (letter[p] == contendor[l]) {
calc [l]= calc [l]+1
}
}
}
for (var f = 0; f < calc.length; f++) {
if ( calc[f] > calc[mycalc]) {
mycalc = f
}
}
}
repeats()
console.log("The most repeated letter its: " + contendor[mycalc]);
I Expected: A result with concise code
It would probably be a lot more concise to use a regular expression: match a character, then lookahead for more characters until you can match that first character again:
var letter = "SYAHSVCXCyXSssssssyBxAVMZsXhZV";
const firstRepeatedRegex = /(.)(?=.*\1)/;
console.log(letter.match(firstRepeatedRegex)[1]);
Of course, if you aren't sure whether a given string contains a repeated character, check that the match isn't null before trying to extract the character:
const input = 'abcde';
const firstRepeatedRegex = /(.)(?=.*\1)/;
const match = input.match(firstRepeatedRegex);
if (match) {
console.log(match[0]);
} else {
console.log('No repeated characters');
}
You could also turn the input into an array and use .find to find the first character whose lastIndexOf is not the same as the index of the character being iterated over:
const getFirstRepeatedCharacter = (str) => {
const chars = [...str];
const char = chars.find((char, i) => chars.lastIndexOf(char) !== i);
return char || 'No repeated characters';
};
console.log(getFirstRepeatedCharacter('abcde'));
console.log(getFirstRepeatedCharacter('SYAHSVCXCyXSssssssyBxAVMZsXhZV'));
If what you're actually looking for is the character that occurs most often, case-insensitive, use reduce to transform the string into an object indexed by character, whose values are the number of occurrences of that character, then identify the largest value:
const getMostRepeatedCharacter = (str) => {
const charsByCount = [...str.toUpperCase()].reduce((a, char) => {
a[char] = (a[char] || 0) + 1;
return a;
}, {});
const mostRepeatedEntry = Object.entries(charsByCount).reduce((a, b) => a[1] >= b[1] ? a : b);
return mostRepeatedEntry[0];
};
console.log(getMostRepeatedCharacter('abcde'));
console.log(getMostRepeatedCharacter('SYAHSVCXCyXSssssssyBxAVMZsXhZV'));
If the first repeated character is what you want, you can push it into an array and check if the character already exists
function getFirstRepeating( str ){
chars = []
for ( var i = 0; i < str.length; i++){
var char = str.charAt(i);
if ( chars.includes( char ) ){
return char;
} else {
chars.push( char );
}
}
return -1;
}
This will return the first repeating character if it exists, or will return -1.
Working
function getFirstRepeating( str ){
chars = []
for ( var i = 0; i < str.length; i++){
var char = str.charAt(i);
if ( chars.includes( char ) ){
return char;
} else {
chars.push( char );
}
}
return -1;
}
console.log(getFirstRepeating("SYAHSVCXCyXSssssssyBxAVMZsXhZV"))
Have you worked with JavaScript objects yet?
You should look into it.
When you loop through your string
let characters = "hemdhdksksbbd";
let charCount = {};
let max = { count: 0, ch: ""}; // will contain max
// rep letter
//Turn string into an array of letters and for
// each letter create a key in the charcount
// object , set it to 1 (meaning that's the first of
// that letter you've found) and any other time
// you see the letter, increment by 1.
characters.split("").forEach(function(character)
{
if(!charCount[character])
charCount[character] = 1;
else
charCount[character]++;
}
//charCount should now contain letters and
// their counts.
//Get the letters from charCount and find the
// max count
Object.keys(charCount). forEach (function(ch){
if(max.count < charCount[ch])
max = { count: charCount[ch], ch: ch};
}
console.log("most reps is: " , max.ch);
This is a pretty terrible solution. It takes 2 loops (reduce) and doesn't handle ties, but it's short and complicated.
Basically keep turning the results into arrays and use array methods split and reduce to find the answer. The first reduce is wrapped in Object.entries() to turn the object back into an array.
let letter = Object.entries(
"SYAHSVCXCyXSssssssyBxAVMZsXhZV".
toUpperCase().
split('').
reduce((p, c) => {
p[c] = isNaN(++p[c]) ? 1 : p[c];
return p;
}, {})
).
reduce((p, c) => p = c[1] > p[1] ? c : p);
console.log(`The most repeated letter is ${letter[0]}, ${letter[1]} times.`);

Find smallest substring containing a given set of letters in a larger string

Say you have the following string:
FJKAUNOJDCUTCRHBYDLXKEODVBWTYPTSHASQQFCPRMLDXIJMYPVOHBDUGSMBLMVUMMZYHULSUIZIMZTICQORLNTOVKVAMQTKHVRIFMNTSLYGHEHFAHWWATLYAPEXTHEPKJUGDVWUDDPRQLUZMSZOJPSIKAIHLTONYXAULECXXKWFQOIKELWOHRVRUCXIAASKHMWTMAJEWGEESLWRTQKVHRRCDYXNT
LDSUPXMQTQDFAQAPYBGXPOLOCLFQNGNKPKOBHZWHRXAWAWJKMTJSLDLNHMUGVVOPSAMRUJEYUOBPFNEHPZZCLPNZKWMTCXERPZRFKSXVEZTYCXFRHRGEITWHRRYPWSVAYBUHCERJXDCYAVICPTNBGIODLYLMEYLISEYNXNMCDPJJRCTLYNFMJZQNCLAGHUDVLYIGASGXSZYPZKLAWQUDVNTWGFFY
FFSMQWUNUPZRJMTHACFELGHDZEJWFDWVPYOZEVEJKQWHQAHOCIYWGVLPSHFESCGEUCJGYLGDWPIWIDWZZXRUFXERABQJOXZALQOCSAYBRHXQQGUDADYSORTYZQPWGMBLNAQOFODSNXSZFURUNPMZGHTAJUJROIGMRKIZHSFUSKIZJJTLGOEEPBMIXISDHOAIFNFEKKSLEXSJLSGLCYYFEQBKIZZTQQ
XBQZAPXAAIFQEIXELQEZGFEPCKFPGXULLAHXTSRXDEMKFKABUTAABSLNQBNMXNEPODPGAORYJXCHCGKECLJVRBPRLHORREEIZOBSHDSCETTTNFTSMQPQIJBLKNZDMXOTRBNMTKHHCZQQMSLOAXJQKRHDGZVGITHYGVDXRTVBJEAHYBYRYKJAVXPOKHFFMEPHAGFOOPFNKQAUGYLVPWUJUPCUGGIXGR
AMELUTEPYILBIUOCKKUUBJROQFTXMZRLXBAMHSDTEKRRIKZUFNLGTQAEUINMBPYTWXULQNIIRXHHGQDPENXAJNWXULFBNKBRINUMTRBFWBYVNKNKDFR
I'm trying to find the smallest substring containing the letters ABCDA.
I tried a regex approach.
console.log(str.match(/[A].*?[B].*?[C].*?[D].*?[A]/gm).sort((a, b) => a.length - b.length)[0]);
This works, but it only find strings where ABCDA appear (in that order). Meaning it won't find substring where the letters appear in a order like this: BCDAA
I'm trying to change my regex to account for this. How would I do that without using | and type out all the different cases?
You can't.
Let's consider a special case: Assume the letters you are looking for are A, A, and B. At some point in your regexp there will certainly be a B. However, the parts to the left and to the right of the B are independent of each other, so you cannot refer from one to the other. How many As are matched in the subexpression to the right of the B depends on the number of As being already matched in the left part. This is not possible with regular expressions, so you will have to unfold all the different orders, which can be many!
Another popular example that illustrates the problem is to match opening brackets with closing brackets. It's not possible to write a regular expression asserting that in a given string a sequence of opening brackets is followed by a sequence of closing brackets of the same length. The reason for this is that to count the brackets you would need a stack machine in contrast to a finite state machine but regular expressions are limited to patterns that can be matched using FSMs.
This algorithm doesn't use a regex, but found both solutions as well.
var haystack = 'FJKAUNOJDCUTCRHBYDLXKEODVBWTYPTSHASQQFCPRMLDXIJMYPVOHBDUGSMBLMVUMMZYHULSUIZIMZTICQORLNTOVKVAMQTKHVRIFMNTSLYGHEHFAHWWATLYAPEXTHEPKJUGDVWUDDPRQLUZMSZOJPSIKAIHLTONYXAULECXXKWFQOIKELWOHRVRUCXIAASKHMWTMAJEWGEESLWRTQKVHRRCDYXNTLDSUPXMQTQDFAQAPYBGXPOLOCLFQNGNKPKOBHZWHRXAWAWJKMTJSLDLNHMUGVVOPSAMRUJEYUOBPFNEHPZZCLPNZKWMTCXERPZRFKSXVEZTYCXFRHRGEITWHRRYPWSVAYBUHCERJXDCYAVICPTNBGIODLYLMEYLISEYNXNMCDPJJRCTLYNFMJZQNCLAGHUDVLYIGASGXSZYPZKLAWQUDVNTWGFFYFFSMQWUNUPZRJMTHACFELGHDZEJWFDWVPYOZEVEJKQWHQAHOCIYWGVLPSHFESCGEUCJGYLGDWPIWIDWZZXRUFXERABQJOXZALQOCSAYBRHXQQGUDADYSORTYZQPWGMBLNAQOFODSNXSZFURUNPMZGHTAJUJROIGMRKIZHSFUSKIZJJTLGOEEPBMIXISDHOAIFNFEKKSLEXSJLSGLCYYFEQBKIZZTQQXBQZAPXAAIFQEIXELQEZGFEPCKFPGXULLAHXTSRXDEMKFKABUTAABSLNQBNMXNEPODPGAORYJXCHCGKECLJVRBPRLHORREEIZOBSHDSCETTTNFTSMQPQIJBLKNZDMXOTRBNMTKHHCZQQMSLOAXJQKRHDGZVGITHYGVDXRTVBJEAHYBYRYKJAVXPOKHFFMEPHAGFOOPFNKQAUGYLVPWUJUPCUGGIXGRAMELUTEPYILBIUOCKKUUBJROQFTXMZRLXBAMHSDTEKRRIKZUFNLGTQAEUINMBPYTWXULQNIIRXHHGQDPENXAJNWXULFBNKBRINUMTRBFWBYVNKNKDFR';
var needle = 'ABCDA'; // the order of letters doesn't matter
var letters = {};
needle.split('').forEach(function(ch) {
letters[ch] = letters[ch] || 0;
letters[ch]++;
});
var shortestSubstringLength = haystack.length;
var shortestSubstrings = []; // storage for found substrings
var startingPos = 0;
var length;
var currentPos;
var notFound;
var letterKeys = Object.keys(letters); // unique leters
do {
lettersLeft = JSON.parse(JSON.stringify(letters)); // copy letters count object
notFound = false;
posStart = haystack.length;
posEnd = 0;
letterKeys.forEach(function(ch) {
currentPos = startingPos;
while (!notFound && lettersLeft[ch] > 0) {
currentPos = haystack.indexOf(ch, currentPos);
if (currentPos >= 0) {
lettersLeft[ch]--;
posStart = Math.min(currentPos, posStart);
posEnd = Math.max(currentPos, posEnd);
currentPos++;
} else {
notFound = true;
}
}
});
if (!notFound) {
length = posEnd - posStart + 1;
startingPos = posStart + 1; // starting position for next iteration
}
if (!notFound && length === shortestSubstringLength) {
shortestSubstrings.push(haystack.substr(posStart, length));
}
if (!notFound && length < shortestSubstringLength) {
shortestSubstrings = [haystack.substr(posStart, length)];
shortestSubstringLength = length;
}
} while (!notFound);
console.log(shortestSubstrings);
Maybe not as clear as using regex could be (well, for me regex are never really clear :D ) you can use brute force (not so brute)
Create an index of "valid" points of your string (those with the letters you want) and iterate with a double loop over it getting substrings containing at least 5 of those points, checking that they are valid solutions. Maybe not the most efficient way, but easy to implement, to understand, and probably to optimize.
var haystack="UGDVWUDDPRQLUZMSZOJPSIKAIHLTONYXAULECXXKWFQOIKELWOHRVRUCXIAASKHMWTMAJEWGEESLWRTQKVHRRCDYXNTLDSUPXMQTQDFAQAPYBGXPOLOCLFQNGNKPKOBHZWHRXAWAWJKMTJSLDLNHMUGVVOPSAMRUJEYUOBPFNEHPZZCLPNZKWMTCXERPZRFKSXVEZTYCXFRHRGEITWHRRYPWSVAYBUHCERJXDCYAVICPTNBGIODLYLMEYLISEYNXNMCDPJJRCTLYNFMJZQNCLAGHUDVLYIGASGXSZYPZKLAWQUDVNTWGFFYFFSMQWUNUPZRJMTHACFELGHDZEJWFDWVPYOZEVEJKQWHQAHOCIYWGVLPSHFESCGEUCJGYLGDWPIWIDWZZXRUFXERABQJOXZALQOCSAYBRHXQQGUDADYSORTYZQPWGMBLNAQOFODSNXSZFURUNPMZGHTAJUJROIGMRKIZHSFUSKIZJJTLGOEEPBMIXISDHOAIFNFEKKSLEXSJLSGLCYYFEQBKIZZTQQXBQZAPXAAIFQEIXELQEZGFEPCKFPGXULLAHXTSRXDEMKFKABUTAABSLNQBNMXNEPODPGAORYJXCHCGKECLJVRBPRLHORREEIZOBSHDSCETTTNFTSMQPQIJBLKNZDMXOTRBNMTKHHCZQQMSLOAXJQKRHDGZVGITHYGVDXRTVBJEAHYBYRYKJAVXPOKHFFMEPHAGFOOPFNKQAUGYLVPWUJUPCUGGIXGR";
var needle="ABCD";
var size=haystack.length;
var candidate_substring="";
var minimal_length=size;
var solutions=new Array();
var points=Array();
for(var i=0;i<size;i++){
if(needle.indexOf(haystack[i])>-1) points.push(i);
}
var limit_i= points.length-4;
var limit_k= points.length;
for (var i=0;i<limit_i;i++){
for(var k=i;k<limit_k;k++){
if(points[k]-points[i]+1<=minimal_length){
candidate_substring=haystack.substr(points[i],points[k]-points[i]+1);
if(is_valid(candidate_substring)){
solutions.push(candidate_substring);
if(candidate_substring.length < minimal_length) minimal_length=candidate_substring.length;
}
}
}
}
document.write('<p>Solution length:'+minimal_length+'<p>');
for(var i=0;i<solutions.length;i++){
if(solutions[i].length<=minimal_length) document.write('<p>Solution:'+solutions[i]+'<p>');
}
function is_valid(candidate_substring){
//verify we've got all characters
for(var j=0;j<candidate_substring.length;j++){
if(candidate_substring.indexOf(needle.charAt(j))<0) return false;
}
//...and verify we have two "A"
if(candidate_substring.indexOf("A")==candidate_substring.lastIndexOf("A")) return false;
return true;
}
Just had this problem in an interview as a coding assignment and came up with another solution, (it's not as optimal as the one above but maybe it's easier to understand).
function MinWindowSubstring(strArr) {
const N = strArr[0];
const K = strArr[1];
const letters = {};
K.split('').forEach( (character) => {
letters[character] = letters[character] ? letters[character] + 1 : 1;
});
let possibleSequencesList = [];
const letterKeys = Object.keys(letters);
for(let i=0; i< N.length; i++) {
const char = N[i];
if (new String(letterKeys).indexOf(char) !== -1) {
// found a character in the string
// update all previus sequences
possibleSequencesList.forEach((seq) => {
if(!seq.sequenceComplete) {
seq[char] = seq[char]-1;
seq.lastIndex = i;
// check if sequence is complete
var sequenceComplete = true;
letterKeys.forEach( (letter) => {
if(seq[letter] > 0) {
sequenceComplete = false;
}
});
seq.sequenceComplete = sequenceComplete
}
})
// create a new sequence starting from it
const newSeq = {
startPoint: i,
lastIndex: i,
sequenceComplete: false,
...letters
}
newSeq[char] = newSeq[char]-1;
possibleSequencesList.push(newSeq);
}
}
// cleanup sequences
let sequencesList = possibleSequencesList.filter(sequence => sequence.sequenceComplete);
let output = [];
let minLength = N.length;
// find the smalles one
sequencesList.forEach( seq => {
if( (seq.lastIndex - seq.startPoint) < minLength) {
minLength = seq.lastIndex - seq.startPoint;
output = N.substring(seq.startPoint, seq.lastIndex + 1);
}
})
return output;
}

for loop iterating over same item 3 times before moving on javascript

I've created a function that returns the longest word of a string. To achieve this the string has been split into an array and iterated through with a for loop.
For some reason the for loop is iterating 3 times over the same item before increasing its count ? There is no obvious error I can see.
What is happening here, how do I stop it ? Also is there a better way to achieve what I'm trying to do here ? I'm relatively new to javascript.
function longWord(str) {
var wordArr = str.split(' ');
var highest = 0;
var longestWd ;
for(var i = 0; i < wordArr.length; i++) {
var temp = wordArr[i].length
var word = wordArr[i];
if(temp > highest) {
highest = temp;
longestWd = word;
}
alert(longestWd);
alert(highest);
}
}
longWord('this is a string with a longest word');
Your code is just fine. If you replace the alerts to a console.log call like this:
console.log(i, word, longestWd)
You can see it works as expectd:
0 "this" "this"
1 "is" "this"
2 "a" "this"
3 "string" "string"
4 "with" "string"
5 "a" "string"
6 "longest" "longest"
7 "word" "longest"
A nice way to do this can be by using reduce like this:
function longWord(str){
return str.split(' ').reduce(function(a, b){
return a.length > b.length ? a : b;
});
}
The reduce() method applies a function against an accumulator and each
value of the array (from left-to-right) has to reduce it to a single
value.
Your alerts are inside of your loop. So, the longest word and its length will be alerted for each word that is tested.
For example:
TEST LONGEST
---- -------
this this <- these are the three you are talking about
is this <- these are the three you are talking about
a this <- these are the three you are talking about
string string
with string
a string
longest longest
word longest
Try moving the alerts outside of the for loop so that the alerts happen after all words have been tested, like this:
function longWord(str) {
var wordArr = str.split(' ');
var highest = 0;
var longestWd;
for (var i = 0; i < wordArr.length; i++) {
var temp = wordArr[i].length
var word = wordArr[i];
if (temp > highest) {
highest = temp;
longestWd = word;
}
}
alert(longestWd);
alert(highest);
}
longWord('this is a string with a longest word');
http://jsfiddle.net/L7HP5/
Your code is not wrong. it's just iterating 3 times over 'this' as it's the longest word.
Based on your code:
function longWord(a){
a = a.split(' ');
var b = a.length,
c = '';
while(b--){
c = c.length < a[b].length ? a[b] : c
}
return c;
}
DEMO
http://jsfiddle.net/8KQK9/1/
PERFORMANCE
http://jsperf.com/longword

Count the number of occurrences of a character in a string in Javascript

I need to count the number of occurrences of a character in a string.
For example, suppose my string contains:
var mainStr = "str1,str2,str3,str4";
I want to find the count of comma , character, which is 3. And the count of individual strings after the split along comma, which is 4.
I also need to validate that each of the strings i.e str1 or str2 or str3 or str4 should not exceed, say, 15 characters.
I have updated this answer. I like the idea of using a match better, but it is slower:
console.log(("str1,str2,str3,str4".match(/,/g) || []).length); //logs 3
console.log(("str1,str2,str3,str4".match(new RegExp("str", "g")) || []).length); //logs 4
Use a regular expression literal if you know what you are searching for beforehand, if not you can use the RegExp constructor, and pass in the g flag as an argument.
match returns null with no results thus the || []
The original answer I made in 2009 is below. It creates an array unnecessarily, but using a split is faster (as of September 2014). I'm ambivalent, if I really needed the speed there would be no question that I would use a split, but I would prefer to use match.
Old answer (from 2009):
If you're looking for the commas:
(mainStr.split(",").length - 1) //3
If you're looking for the str
(mainStr.split("str").length - 1) //4
Both in #Lo's answer and in my own silly performance test split comes ahead in speed, at least in Chrome, but again creating the extra array just doesn't seem sane.
There are at least five ways. The best option, which should also be the fastest (owing to the native RegEx engine) is placed at the top.
Method 1
("this is foo bar".match(/o/g)||[]).length;
// returns 2
Method 2
"this is foo bar".split("o").length - 1;
// returns 2
Split not recommended as it is resource hungry. It allocates new instances of 'Array' for each match. Don't try it for a >100MB file via FileReader. You can observe the exact resource usage using Chrome's profiler option.
Method 3
var stringsearch = "o"
,str = "this is foo bar";
for(var count=-1,index=-2; index != -1; count++,index=str.indexOf(stringsearch,index+1) );
// returns 2
Method 4
Searching for a single character
var stringsearch = "o"
,str = "this is foo bar";
for(var i=count=0; i<str.length; count+=+(stringsearch===str[i++]));
// returns 2
Method 5
Element mapping and filtering. This is not recommended due to its overall resource preallocation rather than using Pythonian 'generators':
var str = "this is foo bar"
str.split('').map( function(e,i){ if(e === 'o') return i;} )
.filter(Boolean)
//>[9, 10]
[9, 10].length
// returns 2
Share:
I made this gist, with currently 8 methods of character-counting, so we can directly pool and share our ideas - just for fun, and perhaps some interesting benchmarks :)
Add this function to sting prototype :
String.prototype.count=function(c) {
var result = 0, i = 0;
for(i;i<this.length;i++)if(this[i]==c)result++;
return result;
};
usage:
console.log("strings".count("s")); //2
Simply, use the split to find out the number of occurrences of a character in a string.
mainStr.split(',').length // gives 4 which is the number of strings after splitting using delimiter comma
mainStr.split(',').length - 1 // gives 3 which is the count of comma
A quick Google search got this (from http://www.codecodex.com/wiki/index.php?title=Count_the_number_of_occurrences_of_a_specific_character_in_a_string#JavaScript)
String.prototype.count=function(s1) {
return (this.length - this.replace(new RegExp(s1,"g"), '').length) / s1.length;
}
Use it like this:
test = 'one,two,three,four'
commas = test.count(',') // returns 3
You can also rest your string and work with it like an array of elements using
Array.prototype.filter()
const mainStr = 'str1,str2,str3,str4';
const commas = [...mainStr].filter(l => l === ',').length;
console.log(commas);
Or
Array.prototype.reduce()
const mainStr = 'str1,str2,str3,str4';
const commas = [...mainStr].reduce((a, c) => c === ',' ? ++a : a, 0);
console.log(commas);
UPDATE: This might be simple, but it is not the fastest. See benchmarks below.
It's amazing that in 13 years, this answer hasn't shown up. Intuitively, it seems like it should be fastest:
const s = "The quick brown fox jumps over the lazy dog.";
const oCount = s.length - s.replaceAll('o', '').length;
If there are only two kinds of character in the string, then this is faster still:
const s = "001101001";
const oneCount = s.replaceAll('0', '').length;
BENCHMARKS
const { performance } = require('node:perf_hooks');
const ITERATIONS = 10000000;
const TEST_STRING = "The quick brown fox jumps over the lazy dog.";
console.log(ITERATIONS, "iterations");
let sum = 0; // make sure compiler doesn't optimize code out
let start = performance.now();
for (let i = 0; i < ITERATIONS; ++i) {
sum += TEST_STRING.length - TEST_STRING.replaceAll('o', '').length;
}
let end = performance.now();
console.log(" replaceAll duration", end - start, `(sum ${sum})`);
sum = 0;
start = performance.now();
for (let i = 0; i < ITERATIONS; ++i) {
sum += TEST_STRING.split('o').length - 1
}
end = performance.now();
console.log(" split duration", end - start, `(sum ${sum})`);
10000 iterations
replaceAll duration 2.6167500019073486 (sum 40000)
split duration 2.0777920186519623 (sum 40000)
100000 iterations
replaceAll duration 17.563208997249603 (sum 400000)
split duration 8.087624996900558 (sum 400000)
1000000 iterations
replaceAll duration 128.71587499976158 (sum 4000000)
split duration 64.15841698646545 (sum 4000000)
10000000 iterations
replaceAll duration 1223.3415840268135 (sum 40000000)
split duration 629.1629169881344 (sum 40000000)
Here is a similar solution, but it uses Array.prototype.reduce
function countCharacters(char, string) {
return string.split('').reduce((acc, ch) => ch === char ? acc + 1: acc, 0)
}
As was mentioned, String.prototype.split works much faster than String.prototype.replace.
If you are using lodash, the _.countBy method will do this:
_.countBy("abcda")['a'] //2
This method also work with array:
_.countBy(['ab', 'cd', 'ab'])['ab'] //2
ok, an other one with regexp - probably not fast, but short and better readable then others, in my case just '_' to count
key.replace(/[^_]/g,'').length
just remove everything that does not look like your char
but it does not look nice with a string as input
I have found that the best approach to search for a character in a very large string (that is 1 000 000 characters long, for example) is to use the replace() method.
window.count_replace = function (str, schar) {
return str.length - str.replace(RegExp(schar), '').length;
};
You can see yet another JSPerf suite to test this method along with other methods of finding a character in a string.
Performance of Split vs RegExp
var i = 0;
var split_start = new Date().getTime();
while (i < 30000) {
"1234,453,123,324".split(",").length -1;
i++;
}
var split_end = new Date().getTime();
var split_time = split_end - split_start;
i= 0;
var reg_start = new Date().getTime();
while (i < 30000) {
("1234,453,123,324".match(/,/g) || []).length;
i++;
}
var reg_end = new Date().getTime();
var reg_time = reg_end - reg_start;
alert ('Split Execution time: ' + split_time + "\n" + 'RegExp Execution time: ' + reg_time + "\n");
I made a slight improvement on the accepted answer, it allows to check with case-sensitive/case-insensitive matching, and is a method attached to the string object:
String.prototype.count = function(lit, cis) {
var m = this.toString().match(new RegExp(lit, ((cis) ? "gi" : "g")));
return (m != null) ? m.length : 0;
}
lit is the string to search for ( such as 'ex' ), and cis is case-insensitivity, defaulted to false, it will allow for choice of case insensitive matches.
To search the string 'I love StackOverflow.com' for the lower-case letter 'o', you would use:
var amount_of_os = 'I love StackOverflow.com'.count('o');
amount_of_os would be equal to 2.
If we were to search the same string again using case-insensitive matching, you would use:
var amount_of_os = 'I love StackOverflow.com'.count('o', true);
This time, amount_of_os would be equal to 3, since the capital O from the string gets included in the search.
Easiest way i found out...
Example-
str = 'mississippi';
function find_occurences(str, char_to_count){
return str.split(char_to_count).length - 1;
}
find_occurences(str, 'i') //outputs 4
Here is my solution. Lots of solution already posted before me. But I love to share my view here.
const mainStr = 'str1,str2,str3,str4';
const commaAndStringCounter = (str) => {
const commas = [...str].filter(letter => letter === ',').length;
const numOfStr = str.split(',').length;
return `Commas: ${commas}, String: ${numOfStr}`;
}
// Run the code
console.log(commaAndStringCounter(mainStr)); // Output: Commas: 3, String: 4
Here you find my REPL
I just did a very quick and dirty test on repl.it using Node v7.4. For a single character, the standard for loop is quickest:
Some code:
// winner!
function charCount1(s, c) {
let count = 0;
c = c.charAt(0); // we save some time here
for(let i = 0; i < s.length; ++i) {
if(c === s.charAt(i)) {
++count;
}
}
return count;
}
function charCount2(s, c) {
return (s.match(new RegExp(c[0], 'g')) || []).length;
}
function charCount3(s, c) {
let count = 0;
for(ch of s) {
if(c === ch) {
++count;
}
}
return count;
}
function perfIt() {
const s = 'Hello, World!';
const c = 'o';
console.time('charCount1');
for(let i = 0; i < 10000; i++) {
charCount1(s, c);
}
console.timeEnd('charCount1');
console.time('charCount2');
for(let i = 0; i < 10000; i++) {
charCount2(s, c);
}
console.timeEnd('charCount2');
console.time('charCount3');
for(let i = 0; i < 10000; i++) {
charCount2(s, c);
}
console.timeEnd('charCount3');
}
Results from a few runs:
perfIt()
charCount1: 3.301ms
charCount2: 11.652ms
charCount3: 174.043ms
undefined
perfIt()
charCount1: 2.110ms
charCount2: 11.931ms
charCount3: 177.743ms
undefined
perfIt()
charCount1: 2.074ms
charCount2: 11.738ms
charCount3: 152.611ms
undefined
perfIt()
charCount1: 2.076ms
charCount2: 11.685ms
charCount3: 154.757ms
undefined
Update 2021-Feb-10: Fixed typo in repl.it demo
Update 2020-Oct-24: Still the case with Node.js 12 (play with it yourself here)
UPDATE 06/10/2022
So I ran various perf tests and if your use case allows it, it seems that using split is going to perform the best overall.
function countChar(char: string, string: string): number {
return string.split(char).length - 1
}
countChar('x', 'foo x bar x baz x')
I know I am late to the party here but I was rather baffled no one answered this with the most basic of approaches. A large portion of the answers provided by the community for this question are iteration based but all are moving over strings on a per-character basis which is not really efficient.
When dealing with a large string that contains thousands of characters walking over each character to get the occurance count can become rather extraneous not to mention a code-smell. The below solutions take advantage of slice, indexOf and the trusted traditional while loop. These approaches prevent us having to walk over each character and will greatly speed up the time it takes to count occurances. These follow similar logic to that you'd find in parsers and lexical analyzers that require string walks.
Using with Slice
In this approach we are leveraging slice and with every indexOf match we will move our way through the string and eliminate the previous searched potions. Each time we call indexOf the size of the string it searches will be smaller.
function countChar (char: string, search: string): number {
let num: number = 0;
let str: string = search;
let pos: number = str.indexOf(char);
while(pos > -1) {
str = str.slice(pos + 1);
pos = str.indexOf(char);
num++;
}
return num;
}
// Call the function
countChar('x', 'foo x bar x baz x') // 3
Using with IndexOf from position
Similar to the first approach using slice but instead of augmenting the string we are searching it will leverage the from parameter in indexOf method.
function countChar (char: string, str: string): number {
let num: number = 0;
let pos: number = str.indexOf(char);
while(pos > -1) {
pos = str.indexOf(char, pos + 1);
num++;
}
return num;
}
// Call the function
countChar('x', 'foo x bar x baz x') // 3
Personally, I go for the second approach over the first, but both are fine and performant when dealing with large strings but also smaller sized ones too.
s = 'dir/dir/dir/dir/'
for(i=l=0;i<s.length;i++)
if(s[i] == '/')
l++
I was working on a small project that required a sub-string counter. Searching for the wrong phrases provided me with no results, however after writing my own implementation I have stumbled upon this question. Anyway, here is my way, it is probably slower than most here but might be helpful to someone:
function count_letters() {
var counter = 0;
for (var i = 0; i < input.length; i++) {
var index_of_sub = input.indexOf(input_letter, i);
if (index_of_sub > -1) {
counter++;
i = index_of_sub;
}
}
http://jsfiddle.net/5ZzHt/1/
Please let me know if you find this implementation to fail or do not follow some standards! :)
UPDATE
You may want to substitute:
for (var i = 0; i < input.length; i++) {
With:
for (var i = 0, input_length = input.length; i < input_length; i++) {
Interesting read discussing the above:
http://www.erichynds.com/blog/javascript-length-property-is-a-stored-value
What about string.split(desiredCharecter).length-1
Example:
var str = "hellow how is life";
var len = str.split("h").length-1; will give count 2 for character "h" in the above string;
The fastest method seems to be via the index operator:
function charOccurances (str, char)
{
for (var c = 0, i = 0, len = str.length; i < len; ++i)
{
if (str[i] == char)
{
++c;
}
}
return c;
}
console.log( charOccurances('example/path/script.js', '/') ); // 2
Or as a prototype function:
String.prototype.charOccurances = function (char)
{
for (var c = 0, i = 0, len = this.length; i < len; ++i)
{
if (this[i] == char)
{
++c;
}
}
return c;
}
console.log( 'example/path/script.js'.charOccurances('/') ); // 2
function len(text,char){
return text.innerText.split(string).length
}
console.log(len("str1,str2,str3,str4",","))
This is a very short function.
The following uses a regular expression to test the length. testex ensures you don't have 16 or greater consecutive non-comma characters. If it passes the test, then it proceeds to split the string. counting the commas is as simple as counting the tokens minus one.
var mainStr = "str1,str2,str3,str4";
var testregex = /([^,]{16,})/g;
if (testregex.test(mainStr)) {
alert("values must be separated by commas and each may not exceed 15 characters");
} else {
var strs = mainStr.split(',');
alert("mainStr contains " + strs.length + " substrings separated by commas.");
alert("mainStr contains " + (strs.length-1) + " commas.");
}
I'm using Node.js v.6.0.0 and the fastest is the one with index (the 3rd method in Lo Sauer's answer).
The second is:
function count(s, c) {
var n = 0;
for (let x of s) {
if (x == c)
n++;
}
return n;
}
And there is:
function character_count(string, char, ptr = 0, count = 0) {
while (ptr = string.indexOf(char, ptr) + 1) {count ++}
return count
}
Works with integers too!
Here's one just as fast as the split() and the replace methods, which are a tiny bit faster than the regex method (in Chrome and Firefox both).
let num = 0;
let str = "str1,str2,str3,str4";
//Note: Pre-calculating `.length` is an optimization;
//otherwise, it recalculates it every loop iteration.
let len = str.length;
//Note: Don't use a `for (... of ...)` loop, it's slow!
for (let charIndex = 0; charIndex < len; ++charIndex) {
if (str[charIndex] === ',') {
++num;
}
}
var mainStr = "str1,str2,str3,str4";
var splitStr = mainStr.split(",").length - 1; // subtracting 1 is important!
alert(splitStr);
Splitting into an array gives us a number of elements, which will always be 1 more than the number of instances of the character. This may not be the most memory efficient, but if your input is always going to be small, this is a straight-forward and easy to understand way to do it.
If you need to parse very large strings (greater than a few hundred characters), or if this is in a core loop that processes large volumes of data, I would recommend a different strategy.
String.prototype.reduce = Array.prototype.reduce;
String.prototype.count = function(c) {
return this.reduce(((n, x) => n + (x === c ? 1 : 0)), 0)
};
const n = "bugs bunny was here".count("b")
console.log(n)
Similar to the prototype based above, but does not allocate an array for the string. Allocation is the problem of nearly every version above, except the loop variants. This avoids loop code, reusing the browser implemented Array.reduce function.
My solution:
function countOcurrences(str, value){
var regExp = new RegExp(value, "gi");
return str.match(regExp) ? str.match(regExp).length : 0;
}
I know this might be an old question but I have a simple solution for low-level beginners in JavaScript.
As a beginner, I could only understand some of the solutions to this question so I used two nested FOR loops to check each character against every other character in the string, incrementing a count variable for each character found that equals that character.
I created a new blank object where each property key is a character and the value is how many times each character appeared in the string(count).
Example function:-
function countAllCharacters(str) {
var obj = {};
if(str.length!==0){
for(i=0;i<str.length;i++){
var count = 0;
for(j=0;j<str.length;j++){
if(str[i] === str[j]){
count++;
}
}
if(!obj.hasOwnProperty(str[i])){
obj[str[i]] = count;
}
}
}
return obj;
}

Categories