30分钟简单实现对10W+数组字符串进行快速筛选[亲测有效]

编程文档 (56) 2023-08-11 11:12

Hi,大家好,我是编程小6,很荣幸遇见你,我把这些年在开发过程中遇到的问题或想法写出来,今天说一说30分钟简单实现对10W+数组字符串进行快速筛选[亲测有效],希望能够帮助你!!!。

背景

最近想到搜索引擎是如何快速的匹配字符串的,假如数据库录入几十万甚至几千万的数据...那计算量该有多大?

数据来源, 本次测试数据量是12W+条。

暴力激活成功教程

const data = [...] // 假设10W+数组字符

/** * indexOf查找方式 * @param {*} str */
function matchIndexOf(str) {
  console.log('输入', str);
  console.time()
  const match = data.filter((e) => ~e.indexOf(str) === 0)
  console.timeEnd()
}

matchIndexOf('Zach') // 匹配Zach开头

试一下这个性能怎样

测试方式 搜索内容 耗时
暴力激活成功教程 Zach 8.997ms
暴力激活成功教程 J 5.991ms
暴力激活成功教程 Juabc 7.615ms

30分钟简单实现对10W+数组字符串进行快速筛选[亲测有效]_https://bianchenghao6.com/blog_编程文档_第1张

30分钟简单实现对10W+数组字符串进行快速筛选[亲测有效]_https://bianchenghao6.com/blog_编程文档_第2张

30分钟简单实现对10W+数组字符串进行快速筛选[亲测有效]_https://bianchenghao6.com/blog_编程文档_第3张

这个对于小数据还好,但是对于大数据的时候就显得有点鸡肋,那大数据量有没有更好的办法?答案是有,那就是提前对数据做索引,通过key: string[]的形式匹配。下面来讲详细过程:

索引方式搜索

索引方式搜索分几个步骤:

  1. 打好索引。
  2. 用打好索引的数据进行搜索。

先说说要达到的目的结果是什么样子

// 原始数据
const oldData = [
    "Z",
    "Zac",
    "Zs",
    "Zccddasda",
    "Zaxzx",
    "Za",
    "Zacg",
    "Zac",
    "Zacgsdsa",
    ...
]
// 搜索内容
var search = 'Z'

// 已经打好索引的数据
var matchIndexData = {
    'Z': ['Z', 'Zac', 'Zs', 'Z2s', 'Zccddasda'], // 以 Z 开头数据
    'Za': ['Zaxzx', 'Za', 'Zacg', 'Zac', 'Zacgsdsa'], // 以 Za 开头的数据
    'Zac': [...], // 以 Zac 开头的数据
    'Zach': [...], // 以 Zach 开头的数据
    ...
}

// 模拟搜索
console.log(matchIndexData[search])
[
    'Z',
    'Zac',
    'Zs',
    'Z2s',
    'Zccddasda'
]

输入Z进行搜索,得出以Z为key的数组数据

实现方式

思路大概是整个数组循环一次,然后再对各个字符串进行循环,其中累计加当前下标的字符当成key,并把当前字符串设置为value

/** * 创建索引补丁 * @param {Array} data * @returns */
function createPatch(data) {
  const obj = {}
  
  const adds = (item) => {
    let key = ''
    for (let i = 0; i < item.length; i++) {
      const e = item[i];
      key += e
      if (obj[key]) {
        obj[key].push(item)
      } else {
        obj[key] = [item]
      }
    }
  }

  data.forEach(e => adds(e))
  return obj
}

// 创建索引补丁
var matchIndexData = createPatch(data)
var search = 'Zach'

// 模拟搜索
console.time()
const match = matchIndexData[search]
console.timeEnd()

性能对比

测试方式 搜索内容 耗时
索引 Zach 0.113ms
索引 J 0.102ms
索引 Juabc 0.099ms

30分钟简单实现对10W+数组字符串进行快速筛选[亲测有效]_https://bianchenghao6.com/blog_编程文档_第4张

30分钟简单实现对10W+数组字符串进行快速筛选[亲测有效]_https://bianchenghao6.com/blog_编程文档_第5张

30分钟简单实现对10W+数组字符串进行快速筛选[亲测有效]_https://bianchenghao6.com/blog_编程文档_第6张

总体保持在0.1毫秒左右。

索引方式搜索-Map版本

/** * 创建索引补丁 * @param {Array} data * @returns */
function createPatch(data) {
  const map = new Map()
  
  const adds = (item) => {
    let key = ''
    for (let i = 0; i < item.length; i++) {
      const e = item[i];
      key += e
      if (map.has(key)) {
        map.get(key).push(item)
      } else {
        map.set(key, [item])
      }
    }
  }

  data.forEach(e => adds(e))
  return map
}

var map = createPatch(data)

console.time()
map.get('M')
console.timeEnd()

性能对比

测试方式 搜索内容 耗时
索引Map版本 Zach 0.076ms
索引Map版本 J 0.078ms
索引Map版本 Juabc 0.076ms

30分钟简单实现对10W+数组字符串进行快速筛选[亲测有效]_https://bianchenghao6.com/blog_编程文档_第7张

30分钟简单实现对10W+数组字符串进行快速筛选[亲测有效]_https://bianchenghao6.com/blog_编程文档_第8张

30分钟简单实现对10W+数组字符串进行快速筛选[亲测有效]_https://bianchenghao6.com/blog_编程文档_第9张

总结

测试方式 搜索内容 耗时
暴力激活成功教程 Zach 8.997ms
暴力激活成功教程 J 5.991ms
暴力激活成功教程 Juabc 7.615ms
索引 Zach 0.113ms
索引 J 0.102ms
索引 Juabc 0.099ms
索引Map版本 Zach 0.076ms
索引Map版本 J 0.078ms
索引Map版本 Juabc 0.076ms

通过key: value形式搜索字符串的方式比起暴力循环激活成功教程会快狠多,本次测试数据量是12W+条,两种查找方式性能差距7倍。

其次,es6中的Map数据结构和对象性能对比,Map的查找方式快一点,数据量越大越明显,当然也有兼容性要求,如果对兼容性不要求的情况下,尽量使用Map。(Ps:最近面试问了好多位中高级前端,大多数对Map只存在于认识,不懂什么场景下使用)。

通过本文,你能学习到大量字符串搜索Map数据结构

本文源码。

今天的分享到此就结束了,感谢您的阅读,如果确实帮到您,您可以动动手指转发给其他人。

发表回复