Я хотел бы получить индекс каждого перекрывающегося вхождения в данной строке.

Например:

var source = 'NNNHRMSLGGGGEAZZ' var toFind = ['HRMSL', 'NN', 'ZZ', 'GGG'] find(source, toFind) // should print line by line: 'NN' found at index 0 'NN' found at index 1 'HRMSL' found at index 2 'GGG' found at index 8 'GGG' found at index 9 'ZZ' found at index 13 

Как я могу добиться этого без использования циклов for или while ( forEach — это хорошо)?

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

Спасибо за помощь.

libgo

новый участник этого сайта. Будьте внимательны, спрашивая разъяснения, комментируя и отвечая. Проверьте наш

Правила поведения

,

Используйте reduce для создания объекта с ключом в качестве элемента arr и значением в качестве массива индексов, затем выполните итерации по ключам объекта и проверьте, не превышает ли его длина массива 1. Если да, это дублирующий элемент.

 const arr = ["a","v","a"]; const groupByDuplicateElements = arr.reduce((a, e, i) ={amp}gt; { if(!a[e]) { a[e] = []; } a[e].push(i); return a; }, {}); Object.keys(groupByDuplicateElements).forEach(key ={amp}gt; { if(groupByDuplicateElements[key].length {amp}gt; 1) { console.log(`${groupByDuplicateElements[key].join(',')}("${key}")`); } }); 

Вы можете использовать рекурсивный вызов indexOf() чтобы найти перекрывающиеся элементы, предоставив начальный индекс для данного элемента на основе ранее найденного индекса. Затем для каждого элемента в вашем массиве вы можете .flatMap() каждую пару элемент-индекс в свой собственный массив. Затем вы можете отсортировать этот массив и затем перебрать его, используя forEach:

 const source = 'NNNHRMSLGGGGEAZZ'; const toFind = ['HRMSL', 'NN', 'ZZ', 'GGG']; const index = (str, item, i = 0) ={amp}gt; { const idx = str.indexOf(item, i); return idx {amp}gt;= 0 ? [[item, idx], ...index(str, item, idx 1)] : [] } const getIndexPairs = (source, toFind) ={amp}gt; toFind.flatMap(item ={amp}gt; index(source, item)).sort(([,a], [,b])={amp}gt;ab); getIndexPairs(source, toFind).forEach(([item, index]) ={amp}gt; { console.log(item  " found at index: "  index); }); 

Простой способ справиться с перекрывающимися элементами — это перебирать каждый toFind отдельно, а в source строке повторять посимвольно, проверяя, начинается ли стог сена, разрезанный в этой точке, с startsWith иглы:

 const find = (source, toFind) ={amp}gt; { const logs = []; toFind.forEach((find) ={amp}gt; { [...source].forEach((_, index) ={amp}gt; { if (source.slice(index).startsWith(find)) { logs.push(({ index, find })); } }); }); logs.sort((a, b) ={amp}gt; a.index - b.index); logs.forEach(({ find, index}) ={amp}gt; { console.log(`${find} found at index ${index}`); }); }; var source = 'NNNHRMSLGGGGEAZZ' var toFind = ['HRMSL', 'AA', 'ZZ', 'GGG'] find(source, toFind)