# 一. 实现 sample 函数
描述:从数组中获取 n 个唯一 key 的随机元素
参数
- collection (Array|Object): 需要获取随机元素的集合
- n=1: 随机元素的个数
- 返回值 (Array): 返回随机元素组成的数组
# 二. 实现
import copyArray from "./.internal/copyArray.js";
import slice from "./slice.js";
/**
* Gets `n` random elements at unique keys from `array` up to the
* size of `array`.
*
* @since 4.0.0
* @category Array
* @param {Array} array The array to sample.
* @param {number} [n=1] The number of elements to sample.
* @returns {Array} Returns the random elements.
* @example
*
* sampleSize([1, 2, 3], 2)
* // => [3, 1]
*
* sampleSize([1, 2, 3], 4)
* // => [2, 3, 1]
*/
//从数组中获取n个唯一key的随机元素
function sampleSize(array, n) {
n = n == null ? 1 : n; //n默认为1
const length = array == null ? 0 : array.length; //数组长度
if (!length || n < 1) {
//如果数组没有长度或者n小于1,返回空数组
return [];
}
n = n > length ? length : n; //如果n超出了数组长度,就赋值为数组长度,否则不变
let index = -1; //循环索引
const lastIndex = length - 1; //数组最后一个元素的索引
const result = copyArray(array); //复制一份array数组作为结果数组
while (++index < n) {
//遍历n次,每一次随机获取数组中的一个元素,保持key不重复
const rand = index + Math.floor(Math.random() * (lastIndex - index + 1));
//生成随机索引值,每一次范围都比上一次少一个
const value = result[rand]; //结果数组中对应随机索引的值先存下来,然后和result[index]互换位置
result[rand] = result[index];
result[index] = value;
}
return slice(result, 0, n); //调用slice截取0到n的结果数组切片
}
export default sampleSize;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
copyArray.js
/**
* Copies the values of `source` to `array`.
*
* @private
* @param {Array} source The array to copy values from.
* @param {Array} [array=[]] The array to copy values to.
* @returns {Array} Returns `array`.
*/
//复制source数组的值到array里
function copyArray(source, array) {
let index = -1; //循环索引
const length = source.length; //source数组长度
array || (array = new Array(length)); //如果没有array参数,就新建一个和source长度一样的数组作为array
while (++index < length) {
//循环source,复制source的元素到array里
array[index] = source[index];
}
return array; //返回array
}
export default copyArray;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
slice.js
/**
* Creates a slice of `array` from `start` up to, but not including, `end`.
*
* **Note:** This method is used instead of
* [`Array#slice`](https://mdn.io/Array/slice) to ensure dense arrays are
* returned.
*
* @since 3.0.0
* @category Array
* @param {Array} array The array to slice.
* @param {number} [start=0] The start position. A negative index will be treated as an offset from the end.
* @param {number} [end=array.length] The end position. A negative index will be treated as an offset from the end.
* @returns {Array} Returns the slice of `array`.
* @example
*
* var array = [1, 2, 3, 4]
*
* _.slice(array, 2)
* // => [3, 4]
*/
//创建一个数组array的切片,从起始索引到结束索引,不包括结束索引
function slice(array, start, end) {
//array要操作的数组,start起始索引,end结束索引
let length = array == null ? 0 : array.length; //数组长度
if (!length) {
//如果数组长度为0,就返回空数组
return [];
}
start = start == null ? 0 : start; //start起始索引,默认值是0
end = end === undefined ? length : end; //end结束索引,默认是数组长度
if (start < 0) {
//起始索引是负数处理,是负数就相当于从末尾往开头数,也就是和lengh相加
start = -start > length ? 0 : length + start; //和length相加后如果还是小于0就等于0
}
end = end > length ? length : end; //结束索引如果大于length就让它等于length
if (end < 0) {
//处理结束索引是负数
end += length;
}
length = start > end ? 0 : (end - start) >>> 0; //根据start和end计算这个切片的长度,如果起始在结束后面那么切片长度为0,否则相减并且取整
start >>>= 0; //start取整
let index = -1; //循环索引
const result = new Array(length); //创建切片长度的数组作为结果数组
while (++index < length) {
//循环切片长度的次数,给结果数组每一项赋值
result[index] = array[index + start];
}
return result;
}
export default slice;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53