JS: как правильно использовать findIndex в цикле forEach?

Только начинаю осваивать JS, поэтому извиняюсь заранее за вопрос, который более опытным может показаться глупым. Есть тренировочный код:

<html>
<script>
let inputWord = 'mappet'

let lettersArr = inputWord.split('');
                
lettersArr.forEach(function(letter) {
    console.log(letter);
    let index = lettersArr.findIndex(i => i == letter);
    
    if(lettersArr[index] == 'p' && lettersArr[index + 1] == 'p') {
        
        lettersArr[index] = lettersArr[index] + '—';
       
    }
    
});

let withTransfer = lettersArr.join("");

alert(withTransfer);
</script>
</html>

Если в переменной inputWord лежит слово "mappet", то он благополучно срабатывает, вставляя тире между двумя "p", но если в ней "pappet" или любое другое слово, у которого первая буква повторяет те, что удваиваются в середине, то условие не срабатывает. Я думаю, что это из-за findIndex, он берет первое вхождение буквы и проверяет условие. В случае с "pappet первым условием будет неудвоенная p с которой все начинается, вот он и не выполнит условие для "pp" в середине.

Подскажите, пожалуйста, как сделать так, чтобы первая p в слове pappet не мешала вставлять тире в середине. Ломал голову, но ничего не смог придумать.


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

Автор решения: Rudi

Всё верно, метод findIndex вызывает переданную функцию callback один раз для каждого элемента, присутствующего в массиве, до тех пор, пока она не вернёт true. Если такой элемент найден, метод findIndex немедленно вернёт индекс этого элемента.

Метод forEach callback принимает три аргумента "элемент, индекс, массив"

Можно сразу проверять следующий символ на соответствие..

<html>
<script>
let inputWord = 'pappet'

let lettersArr = inputWord.split('');
                
lettersArr.forEach(function(letter,i) {
    if(lettersArr[i] == 'p' && lettersArr[i] == lettersArr[i+1]) lettersArr[i] += "-"
});

let withTransfer = lettersArr.join("");

console.log(withTransfer);
</script>
</html>

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

Если я правильно понял, то надо в любом слове pp заменить на p-p. Тут есть несколько способов решения задачи (тут, конечно, не полный список всевозможных способов, но суть +- будет одна и та же):

  • Если надо только первый попавшийся заменить (через регулярные выражения):

    const pasteDefisBetweenTwoP = (str) => str.replace('pp', 'p-p');
    
    console.log(pasteDefisBetweenTwoP('mappet'));
    console.log(pasteDefisBetweenTwoP('pappet'));
    console.log(pasteDefisBetweenTwoP('mappetmappet'));

  • Если надо только первый попавшийся заменить (через циклы):

    const pasteDefisBetweenTwoP = (str) => {
      const strAsArr = str.split('');
      let savePPindex = null;
      
      for(let i = 0; i < strAsArr.length; ++i) {
        if (strAsArr[i] === 'p' && strAsArr[i + 1] === 'p') {
          savePPindex = i;
          break;
        }
      }
      
      if (savePPindex !== null) strAsArr.splice(savePPindex + 1, 0, '-');
      
      return strAsArr.join('');
    };
    
    console.log(pasteDefisBetweenTwoP('mappet'));
    console.log(pasteDefisBetweenTwoP('pappet'));
    console.log(pasteDefisBetweenTwoP('mappetmappet'));

  • Если надо все заменить (через регулярные выражения) (1):

    const pasteDefisBetweenTwoP = (str) => str.replace(/pp/g, 'p-p');
    
    console.log(pasteDefisBetweenTwoP('mappet'));
    console.log(pasteDefisBetweenTwoP('pappet'));
    console.log(pasteDefisBetweenTwoP('mappetmappet'));

  • Если надо все заменить (через регулярные выражения) (2):

    const pasteDefisBetweenTwoP = (str) => str.replaceAll('pp', 'p-p');
    
    console.log(pasteDefisBetweenTwoP('mappet'));
    console.log(pasteDefisBetweenTwoP('pappet'));
    console.log(pasteDefisBetweenTwoP('mappetmappet'));

  • Если надо все заменить (через циклы) (1):

    const pasteDefisBetweenTwoP = (str) => {
      const strAsArr = str.split('');
      const savePPindexes = [];
      
      for(let i = 0; i < strAsArr.length; ++i) {
        if (strAsArr[i] === 'p' && strAsArr[i + 1] === 'p') {
          savePPindexes.push(i);
        }
      }
      
      for (let i = savePPindexes.length - 1; i >= 0; --i) {
        strAsArr.splice(savePPindexes[i] + 1, 0, '-');
      }
      
      return strAsArr.join('');
    };
    
    console.log(pasteDefisBetweenTwoP('mappet'));
    console.log(pasteDefisBetweenTwoP('pappet'));
    console.log(pasteDefisBetweenTwoP('mappetmappet'));

В этом примере надо идти с конца массива. Потому что мы сохраняли индексы массива в момент, когда в нём ещё не было вставлено ничего. А если начинать вставлять с начала, то правильно отработает только для первой вставки, но сразу после этого индексы других бкув изменятся (а мы сохраняли их в прошлом состоянии) и получится, что мы вставим тире не там где надо. Потому идём с конца, чтобы при вставке тире мы могли спокойно обращаться к старым индексам, потому что после встаки индексы изменятся только у последующих букв, а не предыдущих

  • Если надо все заменить (через циклы) (2):

    const pasteDefisBetweenTwoP = (str) => {
      const strAsArr = str.split('');
      const savePPindexes = [];
      
      for(let i = 0; i < strAsArr.length; ++i) {
        if (strAsArr[i] === 'p' && strAsArr[i + 1] === 'p') {
          strAsArr[i] += '-';
        }
      }
      
      return strAsArr.join('');
    };
    
    console.log(pasteDefisBetweenTwoP('mappet'));
    console.log(pasteDefisBetweenTwoP('pappet'));
    console.log(pasteDefisBetweenTwoP('mappetmappet'));

→ Ссылка