Перебирая массив строк, найдите две строки с наибольшим перекрытием и объедините их. ПОВТОРЯЙТЕ, пока не останется одна струна

У меня есть массив строк с именем «коллекция», как показано ниже. Я хочу перебрать массив и найти строки с наибольшим перекрытием - это самые одинаковые символы в строке. Как только я найду две строки, я хочу добавить новую строку в массив с конкатенацией этих двух строк, а затем удалить исходные строки. Загвоздка в том, что конкатенация должна игнорировать общие символы. Например: «hello wo» и «o world» станут «hello world». Я хочу повторять этот процесс, пока не останется одна строка.

let collection = ["all is well", "ell that en", "hat end", "t ends well"];
let longestOverlap = 0;
let longestOverlapChars = '';

for (i = 0 ; i < collection.length ; i++){
     for (j= i+1 ; j < collection.length ; j++){

        findOverlap(collection[i],collection[j]); 
     }
}

function findOverlap(a, b, originalb) {

  if (a.indexOf(b) >= 0) {
    if (longestOverlapChars.length < b.length){      
      longestOverlapChars = b;
      longestOverlap = longestOverlapChars.length;
      console.info(longestOverlapChars, longestOverlap);
    }


    return console.info(a && originalb) ;
  }

  return findOverlap(a, b.substring(0, b.length - 1));
}

Мои результаты показывают 4 результата в консоли: элл, шляпа эн, тен эн, т конец.

Это показывает случаи перекрытия текста.

Впоследствии «шляпа en» является самой большой, поэтому я хочу объединить две строки, которые имеют это перекрытие. Итак, мой новый массив строк будет выглядеть так: [" все хорошо", "черт возьми, конец", "хорошо кончается"];

Теперь есть 3 строки, и я хочу повторять этот процесс, пока не получу ["все хорошо, что хорошо кончается"].

Может ли кто-нибудь дать мне какое-то направление с моим кодом? Кроме того, любые советы по кодированию будут полезны. Пытаюсь улучшить.

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
0
0
443
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Вот как это может работать:

/*
 * findOverlap: 
 *   "merge" two strings, where the overlapping part is not repeated.
 * Input: 
 *   a, b: the strings to "merge"
 *   retry: this is only used by the internal call. It serves to execute the
 *      function a second time with the two strings in reversed positions
 * Returns:
 *   The merged string. If there is no overlap found, then just join the two
 * Examples:
 *   findOverlap("abcdef", "defghi") === "abcdefghi"
 *   findOverlap("aaa", "zzz") === "aaazzz"
 */
function findOverlap(a, b, retry = true) {
    // If one of the two strings is empty, return the other one. This ensures
    //    that empty strings in the collection do not influence the result.
    if (!a || !b) return a || b;
    // Find the position in a, of the first character of b
    let i = a.indexOf(b[0]);
    while (i > -1) { // As long as there is such an occurrence...
        // Calculate what the size of the overlapping part would be:
        //    This is either the size of the remaining part of a, or
        //    the size of b, when it is a real substring of a:
        let size = Math.min(a.length - i, b.length);
        // See if we have an overlap at this position:
        if (a.slice(i).slice(0, size) === b.slice(0, size)) {
            // Yes! Include the "overflowing" part of b:
            return a + b.slice(size);
        }
        // No match. Try a next position:
        i = a.indexOf(b[0], i+1);
    }
    // The start of b does not overlap with the end of a, so try
    //     the opposite:
    if (retry) return findOverlap(b, a, false); // reversed args
    // If this was already the reversed case, then just concatenate
    return b+a; // Reverse again
}

/*
 * findLongestOverlap: 
 *   find information about the two strings that have the longest overlap.
 * Input: 
 *   collection: an array of strings
 * Returns:
 *   An object with 4 properties:
 *      merged: the merged string, not repeating the overlapping part
 *      i, j: the two indexes in the collection of the contributing strings 
 *      overlapSize: number of characters that are part of the overlap
 * Example:
 *   findLongestOverlap(["abcdef", "defghi", "cdefg"]) returns: 
 *     { merged: "abcdefg", i: 0, j: 2, overlapSize: 4 }
 */
function findLongestOverlap(collection) {
    // Initialise the "best" overlap we have so far (we don't have any yet)
    let longest = { overlapSize: -1 };
    // Iterate all pairs from the collection:
    for (let j = 1; j < collection.length; j++) {
        let b = collection[j];
        for (let i = 0; i < j; i++) {
            let a = collection[i];
            const merged = findOverlap(a, b);
            // Derive the size of the overlap from the merged string:
            const overlapSize = a.length + b.length - merged.length;
            // Did we improve?
            if (overlapSize > longest.overlapSize) {
                // Yes! So keep track of all info we need:
                longest = { merged, i, j, overlapSize };
            }
        }
    }
    return longest;
}

/*
 * reduceToOne: 
 *   merge a series of strings, merging via the greatest overlaps first.
 * Input: 
 *   any number of arguments: all strings
 * Returns:
 *   A single string, which represents the merge
 */
function reduceToOne(...collection) { // Grab all arguments as an array
    // Repeat until the collection is reduced to one element
    for (let i = collection.length; --i; ) {
        // Get information from best possible pair-merge:
        const { merged, i, j } = findLongestOverlap(collection);
        // Remove the original two strings having the longest overlap
        collection.splice(j, 1);
        collection.splice(i, 1);
        // Add the merged string
        collection.push(merged);
    }
    // Return the single string that remains
    return collection[0];
}

// Example run:
let collection = ["all is well", "ell that en", "hat end", "t ends well"];
const result = reduceToOne(...collection); // Spread the array as individual arguments

console.info(result);

Прокомментируйте свой код:

  • Избегайте изменения переменных в функции, которые не являются локальными переменными. Так что в вашем случае действия над longestOverlapChars и longestOverlap нарушают эту передовую практику.
  • Функция findOverlap работает нормально, когда конец a перекрывается с началом b, но она не сможет найти перекрытие, если конецb перекрывается с Началоa.

Вау, спасибо. Это здорово. Не могли бы вы оставить еще несколько комментариев к коду, чтобы я знал, что делает каждая строка?

Helloworld69 09.04.2019 11:11

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

function findOverlap(a, b) {

    function partSubs(a, b, pos) {
        var i = b.length;
        do {
            if (i && a.endsWith(b.slice(0, i))) return [i, a + b.slice(i), pos];
        } while (i--)
    }

    // check full sub
    if (a.includes(b)) return [Infinity, a, pos];
    if (b.includes(a)) return [Infinity, b, pos];

    // get partSubs
    var temp = [partSubs(a, b, [i, j]), partSubs(b, a, [j, i])];
    if (temp[0] && temp[1]) return temp[0][0] > temp[1][0] ? temp[0] : temp[1];
    return temp[0] || temp[1];
}

var collection = ["all is well", "ell that en", "hat end", "t ends well"],
    overlap,
    i, j,
    longest;

while (collection.length > 1) {
    overlap = [];
    for (i = 0; i < collection.length - 1; i++)
        for (j = i + 1; j < collection.length; j++)
            overlap.push(findOverlap(collection[i], collection[j]));

    longest = overlap.reduce((a, b) => a && b ? a[0] > b[0] ? a : b : a || b);
    collection = collection.filter((_, i) => !longest[2].includes(i));
    collection.push(longest[1]);
}

console.info(collection);

Другие вопросы по теме