Henry
Henry

Reputation: 279

JavaScript function to automatically count consecutive letters in a string

I am attempting (unsuccessfully) to write JavaScript function LetterCount to count the consecutive letters in a string (and not the total number).

Ideally: LetterCount("eeeeeoooohhoooee") = [["e", 5],["o",3],["h",2],["o",3],["e",2]]

The following code attempts to count the number of consecutive letters in a string only when I already know what they are:

function LetterCount(str) {
for (var i=0; i<str.length;i++) {
    var arr1=[]; arr2=[]; arr3=[]; arr4=[]; arr5=[];
    var e=0; o=0; h=0; o2=0; e2=0;
    if(str[i]="e") {
        arr1 += "e";
        e++;
    }
    arr1.push(e);
    if(str[i]="o") {
        arr2 += "o";
        o++;
    }
    arr2.push(o);
    if(str[i]="h") {
        arr3 += "h";
        h++;
    }
    arr3.push(h);
    if(str[i]="o") {
        arr4 += "o";
        o2++;
    }
    arr4.push(o2);
    if(str[i]="e") {
        arr5 += "e";
        e2++;
    }
    arr5.push(e2);
}
return arr1.concat(arr2).concat(arr3).concat(arr4).concat(arr5);
}

In the code above, I need to first know what the letters in the string are, and how many of them are present, in what order.

INSTEAD: How do you write a function that will automatically recognize the letter themselves, and then return the count of consecutive letters. Would also be great if the answer is in the following format:

 LetterCount("eeeeeoooohhoooee") = [["e", 5],["o",3],["h",2],["o",3],["e",2]]

Any help is much appreciated!

Upvotes: 6

Views: 12642

Answers (6)

Toygar Saral
Toygar Saral

Reputation: 86

const string = 'acbbaeekzzkeee';

function letterCount(str) {
  return [...str].reduce((acc, letter, index) => {
    if (index === 0 || letter !== str[index - 1]) {
      acc.push([letter, 1]);
    } else {
      acc[acc.length - 1][1]++;
    }
    return acc;
  }, []);
}

const count = letterCount(string);
console.log(count);

  1. ...spread string into array
  2. Loop through it with reduce, which initial value is empty array
  3. if it is first letter or previous letter is not same as letter
  4. Make an array with [letter, 1] and push it into accumulator array (1 is initial count/value)
  5. else increment previous array's value in accumulator's array. Since previous array will have same letter as our current letter
  • So whenever we have new value (non-consecutively) we add an array into array.
  • Else we increment last array's value (it will be same letter)

Upvotes: 0

kennebec
kennebec

Reputation: 104810

You can use a regular expression to match any letter followed by zero or more instances of the same letter.

rx=/([a-zA-Z])\1*/g;

Your example matches ["eeeee","oooo","hh","ooo","ee"].

Using map, return the initial letter and the number of occurrences in a new array for each index.

function letterCount(str) {
  var s = str.match(/([a-zA-Z])\1*/g) || [];
  return s.map(function(itm) {
    return [itm.charAt(0), itm.length];
  });
}

console.log(letterCount("eeeeeoooohhoooee"))

returned value: (Array)

[["e",5],["o",4],["h",2],["o",3],["e",2]]

NOTES:

  1. var s= str.match(/([a-zA-Z])\1/g)||[];*

returns an array of matches (repeated letters) or an empty array([]). Otherwise, if the string does not contain any letters an error would be thrown (from calling map on null).

  1. \1* is used to allow matching instances of a single letter with any or no sequential repetition. '\1+' would not match a single unrepeated letter.

  2. Array map expects a function and passes three arguments- the value at each index, the index number, and a reference to the entire array. In this case, only the value of each index is used, so we can ignore the other arguments.

Upvotes: 18

Jonathan Gray
Jonathan Gray

Reputation: 2609

This is my answer:

function LetterCount(str) {
    var current, i = 0, l = str.length;
    var outputArr = [];
    while(i<l) {
        current = str.charAt(i);
        if(!i++ || outputArr[outputArr.length-1][0] !== current)
            outputArr[outputArr.length] = [current, 1];
        else outputArr[outputArr.length-1][1]++;
        }
    return outputArr;
    }

As a modification to kennebec's (awesome) answer, so that the anonymous function isn't declared each time the parent function is called. This is only to reference a better programming practice in comparison to pure simplicity (this is probably the most efficient method):

var letterCount = (function(){
    var r = /([A-z])\1*/g,
        f = function(itm){
        return [itm.charAt(0), itm.length];
        };
    return function letterCount(str){
        return str.match(r).map(f);
        };
    }());

Upvotes: 2

Leo Cavalcante
Leo Cavalcante

Reputation: 2487

Actually "fixed" ["o",3] to ["o",4] ;)

// node v0.10.31
// assert v1.3.0

var assert = require('assert');

function letterCount(str) {
    var i = 0,
        seq = 0,
        results = [];

    while (i < str.length) {
        var current = str[i],
            next = str[i + 1];

        if (typeof results[seq] === 'undefined') {
            results[seq] = [current, 0];
        }

        results[seq][1]++;

        if (current !== next) {
            seq++;
        }

        i++;
    }

    return results;
}

var actual = letterCount('eeeeeoooohhoooee');
var expected = [["e", 5],["o",4],["h",2],["o",3],["e",2]];

assert.deepEqual(actual, expected);

Upvotes: 2

Clemens Frahnow
Clemens Frahnow

Reputation: 317

function LetterCount(text){
    arr = [];
    letter = text[0];
    counter = 0;
    for (c in text+' '){
        if (text[c] != letter){
            newArr = [letter, counter];
            arr.push(newArr);
            letter = text[c];
            counter = 0;
        }
        counter += 1;
    };
    return arr;
}

Upvotes: 0

gavinhi
gavinhi

Reputation: 11

I'd use a map keyed on the character to store the count of consecutive chars and then build the output structure at the end. I'm not sure I understand exactly what you mean by consecutive based on your example but you can tweak the logic to identify a consecutive number accordingly.

function LetterCount(str) {
  var counts = {};
  for (var i = 0, prevChar = null; i < str.length; i++) {
    var char = str.charAt(i);
    if(counts.hasOwnProperty(char) && char === prevChar) {
      counts[char] = counts[char] + 1;  
    } else if (!counts.hasOwnProperty(char)) {
      counts[char] = 0;
    }
    prevChar = char;
  }
  var res = [];
  for (var char in counts) {
    if (counts.hasOwnProperty(char)) {
      res.push([char,counts[char]);
    }
  }
  return res;
}

Upvotes: 1

Related Questions