如何优化在大量字符串中将特定字符串作为整个字符串的一部分的查找

问题描述

我有两个对象数组,我正在尝试优化作为这些对象一部分的两个字符串之间的匹配。

在最坏的情况下,我必须遍历目标数组中的整个对象。

原点数组:

[ {name: "banana 1"},{name: "banana 2"},{name: "monkey"}]

目标数组:

[ {title: "this is a banana 1"},{title: "this doesnt matter"},{title: "this also doesnt matter"} ]

我必须使用正则表达式为原始数组的每个元素在目标数组上找到匹配项。

在这种情况下,我只会匹配:

香蕉 1 -> 这是香蕉 1

我认为没有比两个循环更好更快的方法了,一个循环用于迭代原始数组,第二个循环在第一个循环中迭代所有目的地,以便为目的地中的每个原始对象找到匹配项数组。

有什么办法可以改善这种情况吗?我想优化它,因为我的数组有很多元素。我一直在尝试寻找如何在 postgres 中实现带有 like 表达式的索引,也许这可以在某种程度上帮助我。

解决方法

您可以将带有下划线 _(也可以是 Symbol)的 Trie 作为属性来表示搜索字符串的结尾。

要获取第一个数组的单词,您可以迭代直到长度(使用 sortes 搜索字符串长度优化)并在另一个循环中检查所有字符。如果最后找到结束指示符,你就找到了一个词。

let shortest = Number.MAX_VALUE;

const
    values = [{ name: "banana 1" },{ name: "banana 2" },{ name: "monkey" }],destinations = [{ title: "this is a banana 1##with some more text" },{ title: "this doesnt matter" },{ title: "this also doesnt matter" }],trie = values.reduce((t,{ name }) => {
        if (shortest > name.length) shortest = name.length;
        [...name].reduce((o,k) => o[k] ??= {},t)._ = true;
        return t;
    },{}),result = destinations.map(({ title }) => {
        for (let i = 0,l = title.length - shortest + 1; i < l; i++) {
            let p = trie;
            for (let j = i; j < title.length; j++) {
                if (!(p = p[title[j]])) break;
                if (p._) return title.slice(i,j + 1);
            }
        }
        return '';
    });
console.log(shortest);
console.log(result);
console.log(trie);
.as-console-wrapper { max-height: 100% !important; top: 0; }