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 |
这个对于小数据还好,但是对于大数据的时候就显得有点鸡肋,那大数据量有没有更好的办法?答案是有,那就是提前对数据做索引,通过key: string[]
的形式匹配。下面来讲详细过程:
索引方式搜索分几个步骤:
先说说要达到的目的结果是什么样子
// 原始数据
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 |
总体保持在0.1毫秒左右。
/** * 创建索引补丁 * @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 |
测试方式 | 搜索内容 | 耗时 |
---|---|---|
暴力激活成功教程 | 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
数据结构。
本文源码。
今天的分享到此就结束了,感谢您的阅读,如果确实帮到您,您可以动动手指转发给其他人。