In the code below, I am trying to check how many times a letter in a string appears. Problem with the code below is that it prints each letter more than once. It needs to collect all the same letters and show the number of times it occurs in the string and display it once.
const string = 'mississippi'
const letters = [...string]
let currentLetter = ''
let letterOccurance = []
for(let i = 0; i < letters.length; i++){
let letterFrequency = letters.filter((letter)=>{
return letter === letters[i]
})
letterOccurance.push([`${letters[i]}`,letterFrequency.length])
}
console.log(letterOccurance)
That's too much code just to get the number of times a letter appears in a string. Try the following code:
const string = 'mississippi';
let frequency = {};
for (let letter of string) {
if (frequency[letter]) {
frequency[letter]++;
} else {
frequency[letter] = 1;
}
}
console.log(frequency);
You're always pushing the letter to the array, whether it already exists there or not:
letterOccurance.push([`${letters[i]}`,letterFrequency.length])
You could check if it exists first:
if (!letterOccurance.find(l => l[0] === letters[i])) {
letterOccurance.push([`${letters[i]}`,letterFrequency.length])
}
Or even skip it entirely if you've already seen it, since the first time you find any letter you already know its complete count:
for(let i = 0; i < letters.length; i++){
if (letterOccurance.find(l => l[0] === letters[i])) {
continue;
}
// the rest of the loop...
}
There's honestly a variety of ways you could step back and re-approach the problem. But for the question about why letters are repeating, that's simply because each iteration of the loop unconditionally appends the letter to the resulting array.
How about writing a more generic item-counting function and then layering countLetters as a simple partial application of the identity function?
const countBy = (fn) => ([...xs]) =>
xs .reduce ((a, x) => {const k = fn (x); a [k] = (a[k] || 0) + 1; return a}, {})
const countLetters = countBy (x => x)
console .log (countLetters ('missisippi'))
countBy is fairly generic. You pass it a function to convert your values to strings, and pass your array of items to the function it returns. Strings are array-like enough that this just works for our simple countLetters. But we could use it for other counts as well, such as:
countBy (x => x .grade) ([{id: 1, grade: 'A'}, {id: 2, grade: 'B'}, {id: 3, grade: 'A'}])
//=> {"A": 2, "B": 1}