add sample
This commit is contained in:
parent
2e2c6a8b3b
commit
85ace80d93
23
README.md
23
README.md
@ -16,7 +16,8 @@ import { matches } from '@yanick/remeda';
|
|||||||
|
|
||||||
## Additional functions
|
## Additional functions
|
||||||
|
|
||||||
### `matches`
|
### `matches(target, matcher)`
|
||||||
|
### `matches(matcher)(target)`
|
||||||
|
|
||||||
Compares the input with the matcher and returns `true` if they match.
|
Compares the input with the matcher and returns `true` if they match.
|
||||||
The matcher can be a function (which will be fed the input and is expected
|
The matcher can be a function (which will be fed the input and is expected
|
||||||
@ -37,3 +38,23 @@ pipe({a:1,b:2}, R.matches({ b: (val) => val < 5 }) ) // => true
|
|||||||
pipe({a:1,b:2}, R.matches({ c: 3 }) ) // => false
|
pipe({a:1,b:2}, R.matches({ c: 3 }) ) // => false
|
||||||
pipe( { 'a': 4, 'b': 5, 'c': 6 }, R.matches({ 'a': 4, 'c': 6 })) // => true
|
pipe( { 'a': 4, 'b': 5, 'c': 6 }, R.matches({ 'a': 4, 'c': 6 })) // => true
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### `sample(target, size | { size: number, repeating: boolean })`
|
||||||
|
### `sample(size | { size: number, repeating: boolean })(target)`
|
||||||
|
|
||||||
|
Returns random elements of the array. If `size` is bigger than the array
|
||||||
|
length and `repeating` is false, returns a number of samples equal to
|
||||||
|
the size of the whole array.
|
||||||
|
|
||||||
|
```
|
||||||
|
sample([1,2,3,4],2); // [3,1]
|
||||||
|
sample([1,2,3,4],{size:5, repeating: true}); // [3,1,2,2,4]
|
||||||
|
sample([1,2,3,4],{size:5, repeating: false}); // [3,1,2,4]
|
||||||
|
R.pipe(
|
||||||
|
[{a: 5}, {a: 1}, {a: 3}],
|
||||||
|
R.sumBy(x => x.a)
|
||||||
|
) // 9
|
||||||
|
R.sample(2)([1,2,3,4]); // [3,1]
|
||||||
|
R.sample({size:5, repeating: true},[1,2,3,4]); // [3,1,2,2,4]
|
||||||
|
R.sample({size:5, repeating: false},[1,2,3,4]); // [3,1,2,4]
|
||||||
|
```
|
||||||
|
43
src/sample.test.ts
Normal file
43
src/sample.test.ts
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
import { describe, test, expect, vi, afterEach, beforeEach } from 'vitest';
|
||||||
|
import { sample } from './sample';
|
||||||
|
|
||||||
|
const list = [1, 2, 3, 4, 5];
|
||||||
|
|
||||||
|
describe('data first', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
vi.spyOn(global.Math, 'random').mockReturnValue(0.41);
|
||||||
|
});
|
||||||
|
afterEach(() => {
|
||||||
|
vi.spyOn(global.Math, 'random').mockRestore();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('sample of 1', () => {
|
||||||
|
expect(sample(list, 1)).toEqual([3]);
|
||||||
|
});
|
||||||
|
test('sample of 2', () => {
|
||||||
|
expect(sample(list, 2)).toEqual([3, 2]);
|
||||||
|
});
|
||||||
|
test('sample of 20 (> than the array size)', () => {
|
||||||
|
expect(sample(list, 20)).toEqual([3, 2, 4, 1, 5]);
|
||||||
|
});
|
||||||
|
describe('repeating', () => {
|
||||||
|
test('sample of 2', () => {
|
||||||
|
expect(sample(list, { size: 2, repeating: true })).toEqual([3, 3]);
|
||||||
|
});
|
||||||
|
test('sample of 20', () => {
|
||||||
|
expect(sample(list, { size: 20, repeating: true })).toHaveLength(20);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('data last', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
vi.spyOn(global.Math, 'random').mockReturnValue(0.41);
|
||||||
|
});
|
||||||
|
afterEach(() => {
|
||||||
|
vi.spyOn(global.Math, 'random').mockRestore();
|
||||||
|
});
|
||||||
|
test('sample of 2', () => {
|
||||||
|
expect(sample(2)(list)).toEqual([3, 2]);
|
||||||
|
});
|
||||||
|
});
|
83
src/sample.ts
Normal file
83
src/sample.ts
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
import { purry } from 'remeda';
|
||||||
|
|
||||||
|
export interface SampleType {
|
||||||
|
size: number;
|
||||||
|
repeating: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
function _sample<T>(items: Array<T>, options: number | SampleType) {
|
||||||
|
let nbrSamples = typeof options === 'number' ? options : options.size;
|
||||||
|
const repeating = typeof options === 'object' && options?.repeating;
|
||||||
|
|
||||||
|
let size = items.length;
|
||||||
|
|
||||||
|
// we only need a copy if we're in non-repeating mode
|
||||||
|
if (!repeating) items = [...items];
|
||||||
|
|
||||||
|
if (nbrSamples > size && !repeating) nbrSamples = size;
|
||||||
|
|
||||||
|
const sample = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < nbrSamples; i++) {
|
||||||
|
const index = Math.floor(Math.random() * size);
|
||||||
|
|
||||||
|
sample.push(items[index]);
|
||||||
|
|
||||||
|
if (!repeating) {
|
||||||
|
items[index] = items[size - 1];
|
||||||
|
size--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sample;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns random elements of the array.
|
||||||
|
* @param items the array
|
||||||
|
* @param options The number of samples to take. If the same item can be
|
||||||
|
* picked multiple times, you can pass the object `{ size: number, repeating: boolean }`.
|
||||||
|
* If the number of samples to return exceeds the array size, and `repeating`
|
||||||
|
* is false, returns a number of sample equals to the size of the array.
|
||||||
|
* @signature
|
||||||
|
* R.sample(array,size)
|
||||||
|
* R.sample(array, {size, repeating})
|
||||||
|
* @example
|
||||||
|
* R.sample([1,2,3,4],2); // [3,1]
|
||||||
|
* R.sample([1,2,3,4],{size:5, repeating: true}); // [3,1,2,2,4]
|
||||||
|
* R.sample([1,2,3,4],{size:5, repeating: false}); // [3,1,2,4]
|
||||||
|
* R.pipe(
|
||||||
|
* [{a: 5}, {a: 1}, {a: 3}],
|
||||||
|
* R.sumBy(x => x.a)
|
||||||
|
* ) // 9
|
||||||
|
* @data_first
|
||||||
|
* @category Array
|
||||||
|
*/
|
||||||
|
export function sample<T>(items: ReadonlyArray<T>, size: number): Array<T>;
|
||||||
|
export function sample<T>(
|
||||||
|
items: ReadonlyArray<T>,
|
||||||
|
options: SampleType
|
||||||
|
): Array<T>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns random elements of the array.
|
||||||
|
* @param options The number of samples to take. If the same item can be
|
||||||
|
* picked multiple times, you can pass the object `{ size: number, repeating: boolean }`.
|
||||||
|
* If the number of samples to return exceeds the array size, and `repeating`
|
||||||
|
* is false, returns a number of sample equals to the size of the array.
|
||||||
|
* @signature
|
||||||
|
* R.sample(size)(array)
|
||||||
|
* R.sample({size, repeating})(array)
|
||||||
|
* @example
|
||||||
|
* R.sample(2)([1,2,3,4]); // [3,1]
|
||||||
|
* R.sample({size:5, repeating: true},[1,2,3,4]); // [3,1,2,2,4]
|
||||||
|
* R.sample({size:5, repeating: false},[1,2,3,4]); // [3,1,2,4]
|
||||||
|
* @data_last
|
||||||
|
* @category Array
|
||||||
|
*/
|
||||||
|
export function sample(size: number): <T>(items: Array<T>) => Array<T>;
|
||||||
|
export function sample(options: SampleType): <T>(items: Array<T>) => Array<T>;
|
||||||
|
|
||||||
|
export function sample() {
|
||||||
|
return purry(_sample, arguments);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user