likes
comments
collection
share

100万条数据查找指定元素性能对比

作者站长头像
站长
· 阅读数 70

“我报名参加金石计划1期挑战——瓜分10万奖池,这是我的第2篇文章,点击查看活动详情

首先提出问题:

[1,2,3,4...].includes(2) 比执行for循环更快吗?Array.indexOf更好吗

数组中查找某个元素应该是我们在实际开发中遇到高频问题,那么大家有想过includes,for循环,Arry.indexOf等查找方法究竟那个查找的更快吗?本文将通过真实数据去和大家一步步探讨。

带着上面的疑问,一起来看下结果,本文测试了以下常用方法:

  • includes
  • indexOf
  • findIndex
  • some
  • find
  • existsInArrayFor

第一步,我们需要造一百万条数据, 有同学说那还不简单,直接for循环100万次不就解决了嘛,

var arr = []
for (var i = 0; i < 1000000; i++) {
  arr.push(i)
}

执行了上面的代码我们果真得到了100万长度的数组,但是这不是我们想要的,我们想要的是包含 100 万个字符串的 JSON 数组,每个字符串需要有 500 个随机生成的字符 (这样数据更真实一点) 那有同学说:那再循环1000000次每次生成随机的500个字符串不就行了,试了一下,等了10秒钟之后,浏览器崩了,哈哈~

100万条数据查找指定元素性能对比

function randomString(length = 10) {
  var result = ''
  var characters =
    'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
  var charactersLength = characters.length
  for (var i = 0; i < length; i++) {
    result += characters.charAt(Math.floor(Math.random() * charactersLength))
  }
  return result
}

var arr = []
for (var i = 0; i < 1000000; i++) {
  arr.push(randomString(500))
}

这可咋办啊,这样的大数据直接去js生成肯定不行,我们可以通过node去生成一个包含100万条数据的json文件就可以了,代码如下:

// 生成大数据json文件

const fs = require('fs')

function generateRandomString (length = 10) {
  var result = ''
  var characters =
    'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
  var charactersLength = characters.length
  for (var i = 0;i < length;i++) {
    result += characters.charAt(Math.floor(Math.random() * charactersLength))
  }
  return result
}

function generateFileArray (filePath, length, generator) {
  function writeOpenArray (filePath) {
    fs.writeFileSync(filePath, 'var generatorData = [', {flag: 'a+'})
  }

  function writeCloseArray (filePath) {
    fs.writeFileSync(filePath, ']', {flag: 'a+'})
  }

  function writeArrayEntry (filePath, arr) {
    const stringifiedArray = JSON.stringify(arr)
    let arrayWithoutBrackets = stringifiedArray.slice(1, stringifiedArray.length - 1)
    fs.writeFileSync(filePath, `${arrayWithoutBrackets},`, {flag: 'a+'})
  }
  writeOpenArray(filePath)
  for (let i = 0;i < length;i++) {
    writeArrayEntry(filePath, [generator()])
    console.log(`Progress: ${((i * 100) / length).toFixed(2)}%`)
  }
  writeCloseArray(filePath)
}

function start () {
  const OUTPUT_FILE = './data.json'
  
  // 生成100万条长度随机字符串
  generateFileArray(OUTPUT_FILE, 1000000, () => {
    return generateRandomString(500)
  })
}

start()

通过node执行这个js就能生成100万条数据的json文件了

第二步,我们拿到了一百万条数据之后就要对上面几种方法进行测试了,写一个html去进行测试

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="utf-8" />
  <title>测试</title>
</head>

<body>
</body>
<script src="./data.json"></script>
<script>
  function includes (arr, elem) {
    return arr.includes(elem)
  }

  function indexOf (arr, elem) {
    return arr.indexOf(elem) > -1
  }

  function findIndex (arr, elem) {
    return arr.findIndex((value) => elem === value) > -1
  }

  function some (arr, elem) {
    return arr.some((value) => elem === value) > -1
  }

  function find (arr, elem) {
    return arr.find((e) => e === elem) != null
  }

  function existsInArrayFor (arr, targetElem) {
    for (let i = 0;i < arr.length;i++) {
      if (arr[i] === targetElem) return true
    }
    return false
  }
  
  // 为了保持元素位置,取数组中间位置的值进行查找
  function testFunc (funcName, inputArray) {
    const elementToFind = inputArray[inputArray.length / 2] 
    const start = performance.now()
    const result = funcName(inputArray, elementToFind)
    const end = performance.now()
    console.log(end - start)
    return end - start
  }
</script>

</html>

用Google浏览器对不同方法各自测试了30次之后,去掉最高值和最低值,得到每个方法的消耗的平均时间,结果如下:

  • includes
  • indexOf
  • findIndex
  • some
  • find
  • existsInArrayFor
方法 平均耗时(ms)
includes 11.51
indexOf 11.94
existsInArrayFor 13.98
some 18.26
findIndex 19.75
find 21.62

通过以上的数组可以得到以下两点结论:

  • findsomefindIndex貌似比其他几个慢了不少
  • 在处理大数据字符串时,includesindexOf比其他的方法快了不少

当然上面只是对一组数据进行了测试,可能在不同的模拟数据和机器下表现出来的结果有不同的结果,感兴趣的可以自己试试~

转载自:https://juejin.cn/post/7141288736632864798
评论
请登录