An Interesting way to count letter occurances

Viewed 147

Been stuck on this problem for a bit and need help:

Given an string, count how many times each letter occurs inside a given string; the letters must stay in order of the way the appear in the string with the count next to them. The return must be a single string with letters and count.

Example:

for example: "apple" is "a1p2l1e1", "tees" is "t1e2s1"

I got kinda close with the output format but not quite? this is my code:

function countLetters(str){
    let newArr = []
    let i = 0;
    while(i < str.length){
        if(str.includes(str[i])){
            newArr += str[i];
            newArr += 1;
            i++;
    }
    
}
return newArr;
}; 
console.log(countLetters("apple")); // "a1p2l1e1"

and this is my output:

"a1p1p1l1e1"

Any ideas?

4 Answers

You could use a pattern with a capture group and an optionally repeated backreference \1* to repeat matching the same char of the group.

In the callback of replace, print group 1 which hold the character and concatenate the length of the full match.

The pattern (\S)\1* matches

  • (\S) Capture group 1, match a single non whitespace char
  • \1* Backreference to group 1 and repeat 0+ times to also count a single occurrence

const countLetters = s => s.replace(/(\S)\1*/g, (m, g1) => g1 + m.length);

["apple", "tees"].forEach(s => console.log(countLetters(s)));

Edit

If you want also want to count non adjacent characters in the order you encounter them, you can use a map, increment the value for every key using 1 as a default value and at the end concat the keys and the values.

const countLetters = function(str) {
  const m = new Map;
  let result = "";

  for (let c of str) {
    m.has(c) ? m.set(c, m.get(c) + 1) : m.set(c, 1);
  }
  m.forEach((v, k) => result += k + v);
  return result;
};

["apple", "tees", "banana", "coconut"].forEach(s => console.log(countLetters(s)));

Minimalist approach.

Set allows you to store unique values of any type, Split is the easiest approach to counting char occurrences. If you want better performance checkout: Count the number of occurrences of a character in a string in Javascript

const word = "apple";

let result = "";

[...new Set(word)] // or Array.from(new Set(word))
.forEach((letter) => {
    const frequency = word.split(letter).length - 1;
    result += `${letter}${frequency}`;
});

console.log(result); // a1p2l1e1

The following code seems to work:

function countLetters(str){
  let newArr   = [];
  let i        = 1;
  let lastChar = str[0];
  let count     = 1;

  while(i < str.length) {

    if((str[i]!==lastChar)) {  //if it encounters new character
      newArr += lastChar;
      newArr += count
      lastChar = str[i];
      count=1;
    }
    else {
      count++;
    }
    i++;
  }
  //for the last character
  newArr += lastChar;
  newArr += count
  lastChar = str[i];
  return newArr;
}
console.log(countLetters("apple"));   // a1p2l1e1
console.log(countLetters("banana"));  // b1a1n1a1n1a1

Respecting your question
<< the letters must remain in the order of their appearance in the chain with the count next to them >>

According to the post from The Bomb Squad (unanswered for the moment)

const countLetters = str =>
  [...str].reduce((a,Lc,i,{[i+1]:Ln}) => 
    {
    if (Lc != Ln) { a.r += `${Lc}${++a.n}`; a.n = 0 }
    else          a.n++
    return !!Ln ? a : a.r
    }
    ,{r:'',n:0})

console.log('apple ->', countLetters('apple'));   // 'a1p2l1e1'
console.log('banana ->', countLetters('banana')); // 'b1a1n1a1n1a1'
.as-console-wrapper { max-height: 100% !important; top: 0; }

Related