找出所有字符串的共同部分

时间:2014-05-26 17:55:33

标签: javascript string algorithm search match

我有一个大数组有近10000个字符串,我想在这些字符串中找到所有公共部分(长度超过3个字符)并得到这些部分的出现。

我使用我的简单方法用javascript实现,但它确实花了很多时间,即使我做了一些优化,对于1000个字符串的短数组,Firefox的成本约为8s,Chrome的成本约为12。

所以我想知道是否有任何相关的技术或算法,因为我认为这是一个常见的问题,可以在许多应用程序中提出。

3 个答案:

答案 0 :(得分:1)

构建一个包含所有可能子串的数组,对它们进行排序,然后查找连续相等字符串的块。

下面的实现查找一定长度的后缀并强加最少数量的匹配。目前尚不清楚你想要什么,但你需要一些约束。很容易找到最长的常见后缀,但如果你只是想要常见的后缀,这是什么意思?是否出现了4个字符串的20个出现比10个出现的5个字符串更好?

另请注意,下面的代码不会检查重叠的字符串。如果您查找长度为4的匹配项并且其中包含"green"的30个字词,则结果将同时包含"gree""reen"

它可能不是你想要的,但应该很容易适应。它的速度相当快。在10,000个随机生成的字符串中,每个字符串大约有30个字符,找到长度为10的公共子字符串需要不到一秒钟,对于1000,000个字符串,可能需要4秒。

无论如何,这里是:

/*
 *      Return an array of all substrings of the given length
 *      that occur at least mincount times in all the strings in
 *      the input array strings.
 */
function substrings(strings, length, mincount) {
    var suffix = [];
    var res = [];

    for (var i = 0; i < strings.length; i++) {
        var s = strings[i];

        for (var j = 0; j < s.length - length + 1; j++) {
            suffix.push(s.substr(j, length));
        }
    }

    suffix.sort();
    suffix.push("");

    var last = "";
    var count = 1;
    for (var i = 0; i < suffix.length; i++) {
        var s = suffix[i];

        if (s == last) {
            count++;
        } else {
            if (count >= mincount) res.push(last);
            count = 1;
        }
        last = s;
    }

    return res;
}

答案 1 :(得分:0)

查看Crossfilter http://square.github.io/crossfilter/它将执行您想要的任何类型的地图缩减。但是,通过大混乱搜索Javascript可能会非常缓慢。根据你的约束条件,以及10,000个字符串将如何随着时间的推移而增长,你可能会想到一个RDMS,比如MySQL,因为它们是为这类事物而设计的。

答案 2 :(得分:0)

我遇到了一个稍有不同的问题,我需要找到每个单词的通用前缀,而不仅仅是单词中间或结尾的通用子字符串。此函数将返回一组单词的公共前缀。

        function findCommonPrefixes (words, min) {
            const result = new Set();
            for (const word of words) {
                let partial = word.toLowerCase();
                do {
                    const otherWords = words.filter(w => w !== word).map(w => w.toLowerCase());
                    for (const word of otherWords) {
                        if (word.includes(partial)) {
                            result.add(partial);
                            partial = '';
                            break;
                        }
                    }
                    if (partial) {
                        partial = partial.slice(0, (partial.length - 1))
                    }
                } while (partial.length && partial.length >= min)
            }
            return Array.from(result);
        }