Задача рассчитать и вернуть количество строк

Есть строка.

const stringCount = "ggggaaaazzzzzlllllluuuuuuuuu";

Задача написать функцию которая будет считать количество символов и вернуть такой результат g4a4z5l6u9

У меня получилось вот такой не рабочий код

const str = "ggggaaaazzzzzlllllluuuuuuuuu";


const strNumeric = (str) => {
  let counter = 0,
    currentItem = str[0],
    arr = [];
  [...str].forEach((iterator) => {
    if (iterator !== currentItem) {
      currentItem = iterator;
      arr = [...arr, `${currentItem}${counter}`];
      counter = 0;
    } else {
      counter += 1;
    }
  });
  console.log(arr);
};

console.log(strNumeric(str));

Результат выполнения этого кода такой

[
  "a4",
  "z3",
  "l4",
  "u5"
]

Вторая попытка

const str = "ggggaaaazzzzzlllllluuuuuuuuu";
    
const strNumeric = (str) => {
  let main = [],
    count = 0,
    arr = [];

  [...str].forEach((a) => {
    if (!arr.includes(a)) {
      count = str.match(/a/g, "").length;

      arr = [...arr, a];
      main = [...main, `${a}${count}`];
    } else {
      count = 0;
    }
  });
  console.log(main);
};

strNumeric(str);

Тут уже совсем близок к решению.

Поучаю такой массив -> ["g4", "a4", "z4", "l4", "u4"]

Проблема вот в этой строке -> count = str.match(/a/g, "").length;

Тут всегда получаю 4 почему-то. Почему пока неясно.

Хотелось бы увидеть более понятную реализацию, без однострочных функций и односимвольных переменных, пожалуйста.


Ответы (6 шт):

Автор решения: Алексей Обухов

Моя идея такая: считать в цикле в ассоциативный массив, где ключ - символ, значение - количество символа в строке. Я извиняюсь, что упростил ваш код. Не разбираюсь в бабелях.

const str = "ggggaaaazzzzzlllllluuuuuuuuu";


function strNumeric(s) {
  var tmp = [];
  for (var i = 0; i < s.length; i++) {
    var c = s[i];
    tmp[c] = tmp[c] ? tmp[c] + 1 : 1;
  }

  var res = "";
  for (var c in tmp) {
    res += c + tmp[c];
  }
  return res;
}

console.log(strNumeric(str));

→ Ссылка
Автор решения: WalkMess

Я написал вам функцию, которая вернет объект, теперь с этими данными вы можете делать, что угодно.

const getBufferCountingСharacters = (characters) => {
  buffer = {};
  for (let i = 0; i < characters.length; i++) {
    const character = characters[i];

    if (characters.match(new RegExp(character, 'g')).length > 1) {
      buffer[character] = characters.match(new RegExp(character, 'g')).length;
    }
  }
  return buffer;
};

console.log(getBufferCountingСharacters('ggggaaaazzzzzlllllluuuuuuuuu'));

Однако вот вам решение требующее именно нужный результат. 

const str = Object.entries(getBufferCountingСharacters('ggggaaaazzzzzlllllluuuuuuuuu')).flat().join(''); 
console.log(str);

Обратите внимания, что для работы нужна функция написанная выше.
→ Ссылка
Автор решения: Igor

Если буквы сгруппированы:

const str = "ggggaaaazzzzzlllllluuuuuuuuu";

function strNumeric(s) {
  let r = '';
  while(s) {
    const a = s[0];
    const newS = s.replace(new RegExp(a, 'g'), '');
    r += a + (s.length - newS.length);
    s = newS;
  }
  return r;
}

console.log(strNumeric(str));

Если существует несколько групп для одной и той же буквы:

const str = "ggggaaaazzzzzlllllluuuuuuuuugggggg";

function strNumeric(s) {
  let r = '';
  let count = 1;
  for (let i = 1; i <= s.length; i++) {
    if (s[i] != s[i - 1]) {
      r += s[i - 1] + count;
      count = 0;
    }
    count++;
  }
  return r;
}

console.log(strNumeric(str));

→ Ссылка
Автор решения: RunDevil

Попробуйте так:

let strNumeric = (str) => {
    let map = {};
    let result = "";

    [...str].forEach((char) => {
        !map[char] ? map[char] = 1 : map[char] = map[char] + 1;
    })

    for(let char in map){
        result += char + map[char]
    }

    return result;
}
→ Ссылка
Автор решения: Demon __

Решение:

const str = "ggggaaaazzzlllllluuuuuuuuu";

const strNumeric = (str) => {
  let main = [],
    count = 0,
    arr = [];

  [...str].forEach((item) => {
    if (!arr.includes(item)) {
      count = str.match(new RegExp(item, "g")).length;

      arr = [...arr, item];
      main = [...main, `${item}${count}`];
    } else {
      count = 0;
    }
  });
  return main;
};

console.log(strNumeric(str).join(""));

Спасибо всем за ответы поставил всем плюсики.

→ Ссылка
Автор решения: Избыток Сусликов

Немного похож на ответ @Igor

const stringCount = "ggggaaaazzzzzlllllluuuuuuuuu";

const strNumeric = (str) => {
  // Это строка будет содержать результат выполнения функции в виде строки
  let countedStr = ''; 
  // Переменная для отслеживания повторяющихся символов
  let count = 0; 

  // Если у нас пустая строка выходим из выполнения функции
  if ( str.length === 0 ){
    return;
  } 

  /* 
  * Обычный цикл for для перебора строки
  * Отличие от привычного метода forEach который вы используете в том что
  * тут не нужна разбивка через метод split либо спред оператора
  */    
  for(let i = 0; i < str.length; i++){
    // Счетчик для каждого повторяющегося символа
    count++;
    if (str[i] !== str[i + 1]){
      // Если символ не тот который был ранее добавляем его в countedStr 
      // вместе с count и сбрасываем count
      countedStr += str[i] + count;
      count = 0;
    }
  }
  return countedStr;
}

console.log(strNumeric(stringCount));

Еще есть альтернативный алгоритм который делает обратное

Из этого "g4a4z5l6u9" делает это -> "ggggaaaazzzzzlllllluuuuuuuuu"

const countString = "g4a4z5l6u9";

const strNumeric = (str) => {
  let splittedString = str.split("");
  
  for(let i = 1; i < splittedString.length; i++) {
     if (!isNaN(splittedString[i]) && !isNaN(splittedString[i - 1])) {
      splittedString[i - 1] = splittedString[i - 1] + splittedString[i];
      splittedString.splice(i, 1);
     }
  }
  for (let i = 1; i < splittedString.length; i++ ){
    if ( !isNaN(splittedString[i]) ){
      splittedString[i - 1] = splittedString[i - 1].repeat(Number(splittedString[i]));
      splittedString.splice(i, 1);
    }
  }
  return splittedString.join("");
};

console.log(strNumeric(countString))

Комментарии ко второму коду добавлю потом.

→ Ссылка