-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.ts
122 lines (99 loc) · 3.41 KB
/
index.ts
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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
const words = [
[ 'fuß', 'geschwurbel', 'mate', 'laz0r', 'einhorn' ],
[ 'saft', 'lampe', 'fliege', 'kleber', 'gedöns' ],
[ 'zwerg', 'rundi', 'ülf', 'mauzi', 'hörnchen' ],
[ 'punkt', 'kopf', 'random', 'atom', 'klappe' ],
[ 'demokratie', 'lan', 'sheesh', 'chong' ],
[ 'anne', 'gret', 'kramp', 'karren', 'bauer' ]
].flat();
const randomNumber = (minimum?: number, maximum?: number): number => {
const min = minimum ?? 0;
const max = (maximum ?? Number.MAX_VALUE) - min;
return min + (Math.random() * max);
};
const randomInteger = (minimum?: number, maximum?: number): number => Math.floor(randomNumber(maximum, minimum));
const choose = <TData>(choices: TData[]): TData => choices[randomInteger(choices.length)];
const shuffle = <TData>(values: TData[]): TData[] => {
const shuffledValues = [ ...values ];
for (let i = values.length - 1; i > 0; i--) {
const j = randomInteger(i + 1);
const swap = shuffledValues[i];
shuffledValues[i] = shuffledValues[j];
shuffledValues[j] = swap;
}
return shuffledValues;
};
const sample = <TData>(choices: TData[], sampleSize: number): TData[] => {
if (sampleSize > choices.length) {
throw new Error(
'The sample size cannot be larger than the set of choices, as the sample function draws without replacement. Maybe you are looking for the draw function instead?'
);
}
if (sampleSize === choices.length) {
return choices;
}
const sampledItems = [];
const remainingIndices = new Set<number>(
// eslint-disable-next-line @typescript-eslint/naming-convention
choices.map((_, index): number => index)
);
while (sampledItems.length < sampleSize) {
const nextSampleIndex = choose<number>([ ...remainingIndices ]);
sampledItems.push(choices[nextSampleIndex]);
remainingIndices.delete(nextSampleIndex);
}
return sampledItems;
};
const randomArrayBy = <TData>(generatorFn: (i: number, values: TData[]) => TData, length: number): TData[] =>
Array.from({ length }).
// eslint-disable-next-line @typescript-eslint/naming-convention
map((_: unknown, i: number): number => i).
reduce<TData[]>(
(result, currentIndex): TData[] => [
...result,
generatorFn(currentIndex, result)
],
[]
);
const draw = <TData>(choices: TData[], amount: number): TData[] => randomArrayBy((): TData => choose(choices), amount);
const randomBoolean = (): boolean => choose([ true, false ]);
const randomString = (length?: number): string => {
let word = choose(words);
if (length === undefined) {
return word;
}
while (word.length < length) {
word += choose(words);
}
return word.slice(0, length);
};
const randomObjectBy = <TKey extends string | number | symbol, TValue>(
generatorFn: (i: number, currentObject: Record<TKey, TValue>) => [TKey, TValue],
length = 16
): Record<TKey, TValue> =>
Array.from({ length }).
// eslint-disable-next-line @typescript-eslint/naming-convention
map((_, i): number => i).
reduce<Record<TKey, TValue>>(
(currentObject, i): Record<TKey, TValue> => {
const [ key, value ] = generatorFn(i, currentObject);
return {
...currentObject,
[key]: value
};
},
// eslint-disable-next-line @typescript-eslint/prefer-reduce-type-parameter
{} as Record<TKey, TValue>
);
export {
draw,
choose,
randomArrayBy,
randomBoolean,
randomInteger,
randomNumber,
randomObjectBy,
randomString,
sample,
shuffle
};