spaceDog
spaceDog

Reputation: 461

Count letters in a text and produce an object with results

I am trying to count letters in a text and get an object to display the letter count for each word.

So, for input "Argument here" expected output would be:

{ Argument: { A: 1, r: 2, g: 1, u: 1, m: 1, e: 3, n: 1, t: 1, ' ': 1, h: 1 },
  here: { e: 2, h: 1, r: 1} }

My attempt:

function LetterCountI(str) { 
 var arr = str.split(" "); var cCount = {}; var anotherO = {}; var final = {};
for(var i = 0; i < arr.length; i++){
    if(cCount[arr[i]]){
        cCount[arr[i]]++;
    } else {
        cCount[arr[i]] = 1;
    }
}        

var letterCount = str.split("");
 for(var j = 0; j < letterCount.length; j++){

    if(anotherO[letterCount[j]]){
        anotherO[letterCount[j]]++;
    } else {
        anotherO[letterCount[j]] = 1;
    }
    }

for(var property in cCount){
  final[property] = anotherO;
}

return final;

}

LetterCountI("Argument here");

What I currently get is

{ Argument: { A: 1, r: 2, g: 1, u: 1, m: 1, e: 3, n: 1, t: 1, ' ': 1, h: 1 },
  here: { A: 1, r: 2, g: 1, u: 1, m: 1, e: 3, n: 1, t: 1, ' ': 1, h: 1 } }

Upvotes: 2

Views: 2700

Answers (3)

mrmaclean89
mrmaclean89

Reputation: 586

Using forEach is an easier method, but here's something a bit more vanilla:

function countLetters(string) {
var obj = {};
var arr = string.split(' ');
for (var i = 0; i < arr.length; i++) {
  obj[arr[i]] = {};
  for (var j = 0; j < arr[i].length; j++) {
   if (!obj[arr[i]][arr[i][j]]) {
    obj[arr[i]][arr[i][j]] = 1;
   } else {
    obj[arr[i]][arr[i][j]]++;
  }
}
} return obj;
}



console.log(countLetters("Argument here"));

Upvotes: 0

smnbbrv
smnbbrv

Reputation: 24551

First of all, your approach can fail. If your text just for fun contains __proto__ or another Object property this property will give you an error / unexpected result. Anyway, if you are still sure you want to use this method instead of e.g. hash maps, you can go on with solutions below.

If you care about faster way of doing this you can use the following code:

function count(string) {
  var tmpname = '', tmpvalue = {}, result = {}, i = string.length;

  while (i--) {
    var letter = string[i];

    if (letter === ' ') {
      result[tmpname] = tmpvalue;
      tmpname = '';
      tmpvalue = {};
    }
    else {
      tmpname = letter + tmpname;
      tmpvalue[letter] = (tmpvalue[letter] || 0) + 1;
    }
  }

  if (tmpname) {
    result[tmpname] = tmpvalue;
  }

  return result;
}

console.log(count("Argument here"));

This does not call split function, so it is theoretically faster than Max Mastalerz's solution which does at least 2 full loops by calling a split function two times. If you don't really care about performance or your texts are usually very short, you can use a bit shorter version of Max Mastalerz's solution to approach this:

function count(string) {
  return string.split(' ').reduce(function(a, b) {
    b.split('').reduce(function(c, d) {
      return (c[d] = (c[d] || 0) + 1 , c);
    }, a[b] = {});

    return a;
  }, {});
}

console.log(count("Argument here"));

It is doing just the same, first finding the words and then finding the letters of each word.

Upvotes: 1

Max
Max

Reputation: 2816

JSFiddle, The following will count letters in the words that make up a string:

function letterCounts(s) {
    var result = {};

    s.split(' ').forEach(function(e) {
        result[e] = {};
        e.split('').forEach(function(c) {
            if(!result[e][c]) { result[e][c]=0; }
            result[e][c]++;
        });
    });

    return result;
}

letterCounts('Argument Here');

The result is:

"{"Argument":{"A":1,"r":1,"g":1,"u":1,"m":1,"e":1,"n":1,"t":1},"Here":{"H":1,"e":2,"r":1}}"

enter image description here

Upvotes: 4

Related Questions