0

Essentially, I desire the function to read all letters from a string, and to spit out an object that contains {'letter', 'count'} properties for each letter.

function freqLetters(string) {
  var freq = [];
  for (var i = 0; i < string.length; i++) {
    var character = string.charAt(i);
    if (typeof freq[character] != undefined) {
      freq[character].count++;
    } else {
      freq.push({'letter': character, 'count': 1});
    }
  }

  return freq;
}

However, freq usually appears empty and when it works, it seems to always fail the '!=== undefined' check and push duplicate letters of 1 count, rather than finding them and increment them.

Is the typeof freq[character] !=== undefined] check correct?

How on earth do I increment dynamic elements?

(i.e. find letter:a if it exists, and increment its count by 1 if it exists)

4
  • 1
    Try setting the if as if(typeof freq[character] != "undefined").... Commented Jul 28, 2016 at 5:53
  • It says there is an undefined member of 'count' now.. I try freq[character].count++; and all sorts of while testing, and it seems to just append to the array as if it's a new letter each time(so likely the != undefined still fails) (oops I fixed the ] typo) Commented Jul 28, 2016 at 6:00
  • Ah!! I'm now noticing that you are using the character as index... I wouldn't do that.... Commented Jul 28, 2016 at 6:05
  • As for the if, the != "undefined" part is correct. The problem is with the left part. Commented Jul 28, 2016 at 6:06

3 Answers 3

2

Functional programming woo.

var counts = string
    .split('') // Get individual letters.
    .reduce((acc, letter)=> {
        // acc is an object (passed in as second arg to reduce).
        // we use the existing value for the letter (default to 0) and add one each time.
        acc[letter] = (acc[letter] || 0) + 1
        return acc
    }, {})

Edit: Realized you wanted an array or { letter: count } objects.

var countsList = Object
    .keys(counts)
    .map((key)=> ({ [key]: counts[key] }))
Sign up to request clarification or add additional context in comments.

4 Comments

can make it smaller still changing (key)=> { return { [key]: counts[key] } } to (key)=>({ [key]: counts[key] })
Dude. I never thought about wrapping the returned objects in parans to avoid using returns. Your the bomb.
Nor did I, heh, but it came up recently so thought I'd share
I've used it for 'object switches' like x = ({ a: 1, b: 2, c: 3 })['c'] which is cool but not this.
0

If you want to check existence of letter, don't use an array object. Because push function add element indexed by number (0, 1, 2) so freq[character] is always undefined.

For your instanciation :

var freq = {};

in your else :

freq[character] = {'letter': character, 'count': 1}

And in your if, check just the existence :

if (freq[character]) {... }

1 Comment

Also if you're super paranoid about the presence of keys, you can use if (character in freq) { ... }
0

You could use the below code:

function countCharacters(exampleString){
var countObject = {} ; 
for (var i = 0, l = exampleString.length; i < l; i++) {
    var currentChar =  exampleString.charAt(i);
    if(typeof(currentChar) != undefined) {
        countObject[currentChar] = characterCount(exampleString, currentChar);
    }
}
console.log(countObject);
return(countObject); }



function characterCount(word, character) {
   var count = 0;
    for (var i = 0; i < word.length; i++) {
       if (word[i] === character) {
           count++;
       }
  }
  return count; }

Hope it helps :)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.