【问题标题】:optimize search through large js string array?通过大型js字符串数组优化搜索?
【发布时间】:2011-04-27 21:55:50
【问题描述】:

如果我有一个包含 10,000 多个元素的大型 javascript 字符串数组, 如何快速搜索?

现在我有一个存储工作描述的 javascript 字符串数组, 我允许用户在输入框中动态过滤返回的列表。

假设我有一个这样的字符串数组:
var descArr = {"flipping burgers", "pumping gas", "delivering mail"};

用户想搜索:"p"

如何快速搜索包含 10000 多个描述的字符串数组? 显然,我无法对描述数组进行排序,因为它们是描述,所以二进制搜索不可用。而且由于用户可以通过"p""pi" 或任何字母组合进行搜索,因此这种部分搜索意味着我不能使用关联数组(即searchDescArray["pumping gas"]) 加快搜索速度。

有什么想法吗?

【问题讨论】:

  • 您想在字符串的开头匹配搜索还是在字符串内部进行搜索?如果用户搜索“p”,是否应该在结果中包含“flipping burgers”?
  • descArr 不是数组而是文字对象。
  • @guffa,是的,如果用户搜索“p”,它应该在结果中包含“翻转汉堡”。我发现现在最大的减速是实际搜索。目前我有一个循环遍历数组并进行比较: if (descArray[i].search("P")) > -1){ //return result}
  • 使用正则表达式 - 示例:jsfiddle.net/RnabN/4(30k 字符串,最多 100 个结果)

标签: javascript arrays string search


【解决方案1】:

这可能不是你的答案,因为我正在对你的设置做出一些假设,但如果你有服务器端代码和数据库,你最好进行 AJAX 回调以获得削减列出结果,并使用数据库进行过滤(因为他们非常擅长这种事情)。

除了数据库优势之外,您还可以从不将这么多数据(10000 个变量)输出到基于 Web 的前端中受益 - 如果您只返回您需要的那些,那么您将节省相当多的带宽.

【讨论】:

  • 数据库需要一个全文索引才能适合这项工作,这不是数据库默认实现的,因为它需要大量的存储/内存。使用普通数据库仍然可能更快,因为它执行代码的速度明显快于最坏情况下的浏览器 IE6,但如果它必须处理大量用户,则必须使用专门的索引。
  • @eBusiness - 为此不需要全文索引。在 SQL Server 上,带有 WHERE 标题(如 'P%')的查询仍然是 SARGable,并且如果存在该列,则会使用该列上的索引。它也更快,因为您没有在处理之前通过线路将所有 10000 传输到客户端,而只是将缩减列表传输到客户端。
  • 思考了3年,这是你最好的反驳? %P% 是不可预测的,我相信这就是提问者想要的。
  • 很有趣,昨天刚刚收到该评论的报告... %p% 不是 sargable,但我相信 p% 是。当我再次阅读问题时请注意,我发现我错了......
【解决方案2】:

我建议尝试一个现成的 JS 函数,例如 jQuery 中的 autocomplete。它速度很快,并且有很多配置选项。

查看jQuery autocomplete demo

【讨论】:

  • 您好 medopal,感谢您的建议,但 JQuery 自动完成仅在条目相对较少时才会很快,当大约 10K+ 时它也会变慢
【解决方案3】:

由于实际浏览器中的正则表达式引擎在速度方面变得疯狂,那么这样做怎么样?代替数组传递一个巨大的字符串并用标识符分隔单词。 示例:

  • 字符串"flipping burgers""pumping gas""delivering mail"
  • 正则表达式:"([^"]*ping[^"]*)"

使用全局开关/g,您可以获得所有匹配项。确保用户不搜索您的字符串分隔符。

您甚至可以在字符串中添加一个 id,例如:

  • 字符串"11 flipping burgers""12 pumping gas""13 delivering mail"
  • 正则表达式:"(\d+) ([^"]*ping[^"]*)"

  • 示例:http://jsfiddle.net/RnabN/4/(30000 个字符串,将结果限制为 100 个)

【讨论】:

  • 性能与其说是现代浏览器,不如说是硬件和用户习惯。在现实生活中,与经验丰富的开发人员的计算机相比,普通用户计算机的 2GB RAM 会给出不同的结果。 IT 人员使他们的计算机保持良好状态。
  • 现代正则表达式运行时几乎与预编译的 c++ 程序一样快。旧 javascript (firefox 2/netscape/internet explorer) 和新的即时实现之间存在性能世界。普通电脑上的 chrome 上的 JavaScript 运行速度比带 Internet Explorer 的高端电脑上的 JavaScript 快几倍。
  • 就像提醒未来的小提琴手一样。修改您的 jsfiddle 示例以也接受 ID 号时,数字字符必须双转义: new RegExp('"(\\d+) ([^"]*'+search+'[^"]*)"',' gi')
  • 嗨,您能告诉我如何在您的 plunker 中将大数组转换为“巨大的字符串”吗?谢谢,如果您帮助我,我会投一票,毫无疑问,您的回答很好,但转换数组会也需要一些时间你能提供演示吗?
【解决方案4】:

如果不进行一些更改,就无法加快初始数组查找。您可以通过缓存结果并将其动态映射到模式来加快后续查找。

1.) 调整数据格式。这使得初始查找更快一些。基本上,您预先缓存。

var data = {
    a : ['Ant farm', 'Ant massage parlor'],
    b : ['Bat farm', 'Bat massage parlor']
    // etc
}

2.) 设置缓存机制。

var searchFor = function(str, list, caseSensitive, reduce){
    str = str.replace(/(?:^\s*|\s*$)/g, ''); // trim whitespace
    var found = [];
    var reg = new RegExp('^\\s?'+str, 'g' + caseSensitive ? '':'i');
    var i = list.length;
    while(i--){
        if(reg.test(list[i])) found.push(list[i]);
        reduce && list.splice(i, 1);
    }
}

var lookUp = function(str, caseSensitive){
    str = str.replace(/(?:^\s*|\s*$)/g, ''); // trim whitespace
    if(data[str]) return cache[str];
    var firstChar = caseSensitive ? str[0] : str[0].toLowerCase();
    var list = data[firstChar];
    if(!list) return (data[str] = []);
    // we cache on data since it's already a caching object.
    return (data[str] = searchFor(str, list, caseSensitive)); 
}

3.) 使用以下脚本创建预缓存对象。我建议您运行一次并使用 JSON.stringify 创建一个静态缓存对象。 (或在后端执行此操作)

// we need lookUp function from above, this might take a while
var preCache = function(arr){
    var chars = "abcdefghijklmnopqrstuvwxyz".split('');
    var cache = {};
    var i = chars.length;
    while(i--){
        // reduce is true, so we're destroying the original list here.
        cache[chars[i]] = searchFor(chars[i], arr, false, true);
    }
    return cache;
}

可能比您预期的要多一些代码,但优化和性能并不是免费的。

【讨论】:

  • 我对这种查找机制很感兴趣。但是,我很困惑为什么您只预缓存每个字母?这种方法是否也缓存整个单词?假设您想在 20,000 个字符串的数组中搜索“bat”。
【解决方案5】:

我无法重现该问题,我创建了一个简单的实现,并且大多数浏览器在个位数毫秒内搜索 10000 个 15 字符字符串。我无法在 IE6 中进行测试,但我不相信它比最快的浏览器慢 100 倍以上,这几乎是即时的。

自己尝试一下:http://ebusiness.hopto.org/test/stacktest8.htm(请注意,创建时间与问题无关,只是为了获取一些数据来处理。)

您可能会做错的一件事是尝试呈现所有结果,当用户只输入一个字母或常见的字母组合时,这将是一项艰巨的工作。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-07-04
    • 2010-12-25
    • 2013-09-08
    • 1970-01-01
    • 2022-01-23
    • 2020-03-25
    • 2015-07-30
    相关资源
    最近更新 更多