Skip to content

Commit 2d1159f

Browse files
committed
✨ feature(lib): In the plan, all random string and array functions have been completed, and the code coverage rate is 100%
1 parent c45a5ee commit 2d1159f

21 files changed

+723
-55
lines changed

package.json

+4-1
Original file line numberDiff line numberDiff line change
@@ -74,5 +74,8 @@
7474
"tsup": "^8.0.1",
7575
"typescript": "^5.3.3"
7676
},
77-
"license": "MIT"
77+
"license": "MIT",
78+
"dependencies": {
79+
"decimal.js": "^10.4.3"
80+
}
7881
}

pnpm-lock.yaml

+7
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/index.ts

+8
Original file line numberDiff line numberDiff line change
@@ -1 +1,9 @@
1+
export { default as number } from './number';
2+
export { default as numberStep } from './number/step';
3+
export { default as numberNonConsecutiveFn } from './number/nonConsecutiveFn';
4+
export { default as numbers } from './number/array';
5+
export { default as numbersUnique } from './number/unique';
16
export { default as string } from './string';
7+
export { default as stringNonConsecutiveFn } from './string/nonConsecutiveFn';
8+
export { default as strings } from './string/array';
9+
export { default as stringsUnique } from './string/unique';

src/number/array/index.test.ts

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import array from '.';
2+
3+
describe('@/number/array', () => {
4+
it('生成指定长度和范围的随机数数组', () => {
5+
const result = array(1, 10, 5);
6+
expect(result).toHaveLength(5);
7+
result.forEach((num) => {
8+
expect(num).toBeGreaterThanOrEqual(1);
9+
expect(num).toBeLessThanOrEqual(10);
10+
});
11+
});
12+
13+
it('当步长非0时,生成步长间隔的随机数数组', () => {
14+
const result = array(0, 10, 6, 2);
15+
expect(result).toHaveLength(6);
16+
result.forEach((num) => {
17+
expect(num % 2).toBe(0);
18+
});
19+
});
20+
21+
it('当未指定数量时,默认生成长度为10的数组', () => {
22+
const result = array(1, 10);
23+
expect(result).toHaveLength(10);
24+
});
25+
26+
it('当最小值等于最大值时,数组中所有元素相同', () => {
27+
const result = array(5, 5, 5);
28+
expect(result).toHaveLength(5);
29+
result.forEach((num) => {
30+
expect(num).toBe(5);
31+
});
32+
});
33+
34+
it('当步长为0时,生成最小值和最大值之间的随机数数组', () => {
35+
const result = array(0, 5, 5, 0);
36+
expect(result).toHaveLength(5);
37+
result.forEach((num) => {
38+
expect(num).toBeGreaterThanOrEqual(0);
39+
expect(num).toBeLessThanOrEqual(5);
40+
});
41+
});
42+
});

src/number/array/index.ts

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import stepFn from '@/number/step';
2+
3+
/**
4+
* 生成指定数量的随机数数组
5+
* @param {number} minimum 最小值 (Minimum value)
6+
* @param {number} maximum 最大值 (Maximum value)
7+
* @param {number} [count = 10] 数组长度 (Array length)
8+
* @param {number} [step = 0] 步长,如果为 0 则不限制步长,假设 minimum 为 0,maximum 为 10,step 为 2,则生成的随机数为 0、2、4、6、8、10 (Step size, if it is 0, the step size is not limited, assuming that the minimum is 0, the maximum is 10, and the step is 2, then the generated random number is 0, 2, 4, 6, 8, 10)
9+
* @returns {number[]} 随机数数组 (Random number array)
10+
*/
11+
const array = (minimum: number, maximum: number, count: number = 10, step: number = 0): number[] => Array.from({ length: count }, () => stepFn(minimum, maximum, step));
12+
13+
export default array;

src/number/index.test.ts

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import number from '.';
2+
3+
describe('@/number/index.ts', () => {
4+
it('应当生成指定范围内的随机数', () => {
5+
const min = 5;
6+
const max = 10;
7+
const result = number(min, max);
8+
expect(result).toBeGreaterThanOrEqual(min);
9+
expect(result).toBeLessThanOrEqual(max);
10+
});
11+
12+
it('当最小值等于最大值时,应当返回该值', () => {
13+
const minMax = 7;
14+
expect(number(minMax, minMax)).toBe(minMax);
15+
});
16+
17+
it('应当正确处理浮点数范围', () => {
18+
const min = 5.5;
19+
const max = 5.9;
20+
const result = number(min, max);
21+
expect(result).toBeGreaterThanOrEqual(min);
22+
expect(result).toBeLessThanOrEqual(max);
23+
});
24+
});

src/number/index.ts

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { Decimal } from 'decimal.js';
2+
3+
/**
4+
* 生成随机数 (Generate random number)
5+
* @param {number} minimum 最小值 (Minimum value)
6+
* @param {number} maximum 最大值 (Maximum value)
7+
* @returns {number} 包含最小值或最大值的随机数 (Random number containing minimum or maximum value)
8+
*/
9+
const number = (minimum: number, maximum: number): number => {
10+
if (minimum === maximum) {
11+
return minimum;
12+
}
13+
14+
const minDecimal = new Decimal(minimum);
15+
const maxDecimal = new Decimal(maximum);
16+
17+
// 计算范围并生成随机数
18+
const range = maxDecimal.minus(minDecimal);
19+
const randomDecimal = Decimal.random().mul(range).plus(minDecimal);
20+
21+
// 确定结果的小数位数
22+
const maxDp = Math.max(minDecimal.dp(), maxDecimal.dp());
23+
24+
// 使用 Decimal 对象进行四舍五入,以确保精度
25+
return randomDecimal.toDecimalPlaces(maxDp, Decimal.ROUND_HALF_UP).toNumber();
26+
};
27+
28+
export default number;
+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import nonConsecutiveFn from '.';
2+
3+
describe('@/number/nonConsecutiveFn', () => {
4+
it('生成的随机数应该是非连续的', () => {
5+
const min = 1;
6+
const max = 10;
7+
const generateRandom = nonConsecutiveFn(min, max);
8+
9+
let prevNumber = generateRandom();
10+
let nonConsecutive = true;
11+
12+
for (let i = 0; i < 100; i++) {
13+
const newNumber = generateRandom();
14+
if (newNumber === prevNumber) {
15+
nonConsecutive = false;
16+
break;
17+
}
18+
prevNumber = newNumber;
19+
}
20+
21+
expect(nonConsecutive).toBe(true);
22+
});
23+
24+
it('生成的随机数应在指定范围内', () => {
25+
const min = 1;
26+
const max = 5;
27+
const generateRandom = nonConsecutiveFn(min, max);
28+
29+
for (let i = 0; i < 100; i++) {
30+
const number = generateRandom();
31+
expect(number).toBeGreaterThanOrEqual(min);
32+
expect(number).toBeLessThanOrEqual(max);
33+
}
34+
});
35+
36+
it('当最小值等于最大值时,应总是返回该值', () => {
37+
const minMax = 3;
38+
const generateRandom = nonConsecutiveFn(minMax, minMax);
39+
40+
for (let i = 0; i < 10; i++) {
41+
expect(generateRandom()).toBe(minMax);
42+
}
43+
});
44+
});

src/number/nonConsecutiveFn/index.ts

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import number from '@/number';
2+
3+
/**
4+
* 生成不连续的随机数,即连续两次生成的随机数100%不相同 (Generate random numbers that are not consecutive, that is, the random numbers generated twice are 100% different)
5+
* @param {number} minimum 最小值 (Minimum value)
6+
* @param {number} maximum 最大值 (Maximum value)
7+
* @returns {() => number} 生成不连续的随机数的函数 (Function that generates random numbers that are not consecutive)
8+
*/
9+
const nonConsecutiveFn = (minimum: number, maximum: number): (() => number) => {
10+
let previousValue: number;
11+
12+
return () => {
13+
// 当最小值等于最大值时,总是返回该值
14+
if (minimum === maximum) {
15+
return minimum;
16+
}
17+
18+
let num: number;
19+
20+
do {
21+
num = number(minimum, maximum);
22+
} while (num === previousValue);
23+
24+
previousValue = num;
25+
return num;
26+
};
27+
};
28+
29+
export default nonConsecutiveFn;

src/number/step/index.test.ts

+84
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
import step from '.';
2+
3+
describe('@/number/step', () => {
4+
it('当最小值和最大值相等时应该直接返回该值', () => {
5+
expect(step(5, 5)).toBe(5);
6+
});
7+
8+
it('步长为0时应该生成最小值和最大值之间的随机数', () => {
9+
const result = step(0, 10);
10+
expect(result).toBeGreaterThanOrEqual(0);
11+
expect(result).toBeLessThanOrEqual(10);
12+
});
13+
14+
it('步长大于最大值和最小值之差时应该返回最小值', () => {
15+
expect(step(0, 5, 10)).toBe(0);
16+
});
17+
18+
it('生成指定步长的随机数', () => {
19+
const result = step(0, 10, 2);
20+
expect([0, 2, 4, 6, 8, 10]).toContain(result);
21+
});
22+
23+
it('生成指定步长的随机整数', () => {
24+
const result = step(0, 100, 10);
25+
expect(result % 10).toBe(0);
26+
expect(result).toBeGreaterThanOrEqual(0);
27+
expect(result).toBeLessThanOrEqual(100);
28+
});
29+
30+
it('生成指定步长的随机小数', () => {
31+
const result = step(0, 1, 0.1);
32+
expect(result).toBeGreaterThanOrEqual(0);
33+
expect(result).toBeLessThanOrEqual(1);
34+
expect(Math.round(result * 10) / 10).toBe(result); // 确保是0.1的倍数
35+
});
36+
37+
it('生成的随机数应该在最小值和最大值之间,并且与最小值的差是步长的倍数', () => {
38+
const min = 2,
39+
max = 12,
40+
stepSize = 3;
41+
const result = step(min, max, stepSize);
42+
43+
expect([2, 5, 8, 11]).toContain(result);
44+
});
45+
46+
it('应该处理浮点步长', () => {
47+
const result = step(0, 1, 0.1);
48+
expect(result).toBeGreaterThanOrEqual(0);
49+
expect(result).toBeLessThanOrEqual(1);
50+
expect(Math.round(result * 10) / 10).toBe(result);
51+
});
52+
53+
it('处理带有小数的步长', () => {
54+
const result = step(0.5, 5.5, 0.3);
55+
expect(result).toBeGreaterThanOrEqual(0.5);
56+
expect(result).toBeLessThanOrEqual(5.5);
57+
expect([0.5, 0.8, 1.1, 1.4, 1.7, 2.0, 2.3, 2.6, 2.9, 3.2, 3.5, 3.8, 4.1, 4.4, 4.7, 5.0, 5.3]).toContain(result);
58+
});
59+
60+
it('应正确处理负数步长', () => {
61+
const result = step(-10, 0, 2);
62+
expect(result).toBeGreaterThanOrEqual(-10);
63+
expect(result).toBeLessThanOrEqual(0);
64+
});
65+
66+
it('生成指定步长的随机小数', () => {
67+
const min = 3.14;
68+
const max = 10;
69+
const stepSize = 2;
70+
const result = step(min, max, stepSize);
71+
expect([3.14, 5.14, 7.14, 9.14]).toContain(result);
72+
});
73+
74+
it('步长大于最大值和最小值之差时返回最小值', () => {
75+
const min = 1;
76+
const max = 6.00000000001;
77+
const stepSize = 10;
78+
expect(step(min, max, stepSize)).toBe(1);
79+
});
80+
81+
it('当步长为负数且绝对值大于最大值和最小值之差时应返回最小值', () => {
82+
expect(step(-5, 0, -6)).toBe(-5);
83+
});
84+
});

src/number/step/index.ts

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import { Decimal } from 'decimal.js';
2+
import number from '@/number';
3+
4+
/**
5+
* 生成指定步长的随机数 (Generate random numbers with specified step size)
6+
* @param {number} minimum 最小值 (Minimum value)
7+
* @param {number} maximum 最大值 (Maximum value)
8+
* @param {number} [step = 0] 步长,如果为 0 则不限制步长,假设 minimum 为 3,maximum 为 10,step 为 2,则生成的随机数为 3 5 7 9 (Step size, if it is 0, the step size is not limited, assuming that the minimum is 3, the maximum is 10, and the step is 2, then the generated random number is 3 5 7 9)
9+
* @returns {number} 包含最小值或最大值的随机数 (Random number containing minimum or maximum value)
10+
*/
11+
const step = (minimum: number, maximum: number, step: number = 0): number => {
12+
// 当最小值和最大值相等时,直接返回该值
13+
if (minimum === maximum) {
14+
return minimum;
15+
}
16+
17+
// 如果步长为0,则生成最小值和最大值之间的随机数
18+
if (step === 0) {
19+
return number(minimum, maximum);
20+
}
21+
22+
const minDecimal = new Decimal(minimum);
23+
const maxDecimal = new Decimal(maximum);
24+
const stepDecimal = new Decimal(step);
25+
26+
// 如果步长大于最大值和最小值之差,则返回最小值
27+
if (stepDecimal.abs().greaterThan(maxDecimal.minus(minDecimal))) {
28+
return minimum;
29+
}
30+
31+
// 根据最小值和步长计算随机数范围
32+
const range = maxDecimal.minus(minDecimal).div(stepDecimal).floor();
33+
const randomIndex = number(0, range.toNumber());
34+
const randomStep = minDecimal.plus(new Decimal(randomIndex).mul(stepDecimal));
35+
36+
// 确定最长的小数位数
37+
const maxDp = Math.max(minDecimal.dp(), maxDecimal.dp(), stepDecimal.dp());
38+
39+
// 使用最长的小数位数来确定结果的精度
40+
return randomStep.toDecimalPlaces(maxDp, Decimal.ROUND_HALF_UP).toNumber();
41+
};
42+
43+
export default step;

0 commit comments

Comments
 (0)