Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

lodash源码分析之sampleSize #164

Open
HeftyKoo opened this issue Mar 27, 2020 · 0 comments
Open

lodash源码分析之sampleSize #164

HeftyKoo opened this issue Mar 27, 2020 · 0 comments
Labels
api 暴露出来的接口 系列文章

Comments

@HeftyKoo
Copy link
Owner

本文为读 lodash 源码的第一百六十三篇,后续文章会更新到这个仓库中,欢迎 star:pocket-lodash

gitbook也会同步仓库的更新,gitbook地址:pocket-lodash

依赖

import copyArray from './.internal/copyArray.js'
import slice from './slice.js'

《lodash源码分析之copyArray》
《读lodash源码之从slice看稀疏数组与密集数组》

源码分析

sampleSizesample 的作用是类似的,不过 sampleSize 会随机返回 array 中指定数量 n 的元素。

源码如下:

function sampleSize(array, n) {
  n = n == null ? 1 : n
  const length = array == null ? 0 : array.length
  if (!length || n < 1) {
    return []
  }
  n = n > length ? length : n
  let index = -1
  const lastIndex = length - 1
  const result = copyArray(array)
  while (++index < n) {
    const rand = index + Math.floor(Math.random() * (lastIndex - index + 1))
    const value = result[rand]
    result[rand] = result[index]
    result[index] = value
  }
  return slice(result, 0, n)
}

参数合规化处理

如果没有传递 n,即没有指定随机的个数,则默认为 1

如果 length0 ,或者 n < 1 ,也即传入的 array 为空数组或者 nullundefined,或者要求的数量小于 1 时,都直接返回空数组。

接下来再判断指定的数量 n 是否超出来数组长度的范围,如果超出,则将 n 重置为 length,这很容易理解,随机的数量最多也只能跟 array 的长度一样。

思路

sample 中的分析我们知道,要从数组中取一个值,只需要取一个随机索引,然后再将该索引对应的值取出即可。那要怎样取一组值呢?

我们按照 sample 的方式,得到一个随机索引,并且将值取出,将这个值放到数组的第一位,再将第一位的值放到这个随机索引的位置。

第二次取随机索引的时候,因为第一位是已经取出来的值,因此随机索引要从第二位开始,再取出一个随机值,和第二位的值进行交换,直至 n 个数取出完成,这样,数组的 0-n 位都是随机取出来的值,只需要将这些值返回即可。

这里用 index 来表示当前已取出的随机值的索引,会不断递增,直至 n 个值取完。

因为会涉及数组元素的交互,会对数组进行更改,因此不能直接操作原数组,需要用 copyArray 对数组进行复制。

可以看到,计算随机索引的公式如下:

index + Math.floor(Math.random() * (lastIndex - index + 1))

lastIndex - index + 1 其实就是数组除已取出的随机值外剩余的数量,对剩余的数量取随机值,然后再加上 index ,避免和已经取出的索引重叠。

计算得出随机索引后,后面的代码其实就是值的交互。

最后使用 slice0-n 的随机值取出即可。

License

署名-非商业性使用-禁止演绎 4.0 国际 (CC BY-NC-ND 4.0)

最后,所有文章都会同步发送到微信公众号上,欢迎关注,欢迎提意见:

作者:对角另一面

@HeftyKoo HeftyKoo added 系列文章 api 暴露出来的接口 labels Mar 27, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
api 暴露出来的接口 系列文章
Projects
None yet
Development

No branches or pull requests

1 participant