Skip to content

Commit

Permalink
feat(sample): Add sample to compat layer (#708)
Browse files Browse the repository at this point in the history
* feat(compat): implement array/sample

* feat(compat): array/sample test code

* feat(compat): array/sample docs

* feat(compat): array/sample bench

* fix(compat): array/sample lint

* Delete docs/ko/reference/compat/array/sample.md

* Delete docs/reference/compat/array/sample.md

* Update src/compat/array/sample.ts

* Update sample.ts

* Update src/compat/array/sample.ts

* Update sample.ts

---------

Co-authored-by: Sojin Park <[email protected]>
  • Loading branch information
Gyumong and raon0211 authored Oct 13, 2024
1 parent 76ec5f1 commit be5ba71
Show file tree
Hide file tree
Showing 4 changed files with 164 additions and 0 deletions.
10 changes: 10 additions & 0 deletions benchmarks/performance/sample.bench.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { bench, describe } from 'vitest';
import { sample as sampleToolkit_ } from 'es-toolkit';
import { sample as sampleToolkitCompat } from 'es-toolkit/compat';
import { sample as sampleLodash_ } from 'lodash';

const sampleToolkit = sampleToolkit_;
Expand All @@ -11,6 +12,11 @@ describe('sample', () => {
sampleToolkit(array);
});

bench('es-toolkit/compat/sample', () => {
const array = [1, 2, 3, 4, 5];
sampleToolkitCompat(array);
});

bench('lodash/sample', () => {
const array = [1, 2, 3, 4, 5];
sampleLodash(array);
Expand All @@ -24,6 +30,10 @@ describe('sample/largeArray', () => {
sampleToolkit(largeArray);
});

bench('es-toolkit/compat/sample', () => {
sampleToolkitCompat(largeArray);
});

bench('lodash/sample', () => {
sampleLodash(largeArray);
});
Expand Down
46 changes: 46 additions & 0 deletions src/compat/array/sample.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { describe, expect, it } from 'vitest';
import { sample } from './sample';
import { noop } from '../../function/noop';
import { empties } from '../_internal/empties';

/**
* @see https://github.com/lodash/lodash/blob/6a2cc1dfcf7634fea70d1bc5bd22db453df67b42/test/sample.spec.js
*/

describe('sample', () => {
const array = [1, 2, 3, 4, 5];

it('should return a random element from an array', () => {
const actual = sample(array);
expect(array).toContain(actual);
});

it('should return `undefined` when sampling empty collections', () => {
const expected = empties.map(noop);

const actual = empties.map(value => {
try {
return sample(value);
} catch (e) {
return undefined;
}
});

expect(actual).toEqual(expected);
});

it('should sample an object', () => {
const object = { a: 1, b: 2, c: 3 };
const actual = sample(object);
const values = Object.values(object);

expect(values).toContain(actual);
});

it('should sample a string', () => {
const str = 'abc';
const actual = sample(str);

expect(['a', 'b', 'c']).toContain(actual);
});
});
107 changes: 107 additions & 0 deletions src/compat/array/sample.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import { sample as sampleToolkit } from '../../array/sample.ts';
import { isArrayLike } from '../predicate/isArrayLike.ts';

/**
* Returns a random element from an array.
*
* @template T
* @param {T[]} array - The array to sample from.
* @returns {T | undefined} A random element from the array, or `undefined` if the array is empty.
*
* @example
* const array = [1, 2, 3];
* const result = sample(array);
* console.log(result); // Output: 1, 2, or 3 (randomly selected)
*/
export function sample<T>(array: readonly T[]): T | undefined;

/**
* Returns a random character from a string.
*
* @param {string} str - The string to sample from.
* @returns {string | undefined} A random character from the string, or `undefined` if the string is empty.
*
* @example
* const str = "hello";
* const result = sample(str);
* console.log(result); // Output: 'h', 'e', 'l', 'l', or 'o' (randomly selected)
*/
export function sample(str: string): string | undefined;

/**
* Returns a random element from an array.
*
* @template T
* @param {ArrayLike<T>} array - The array-like object to sample from.
* @returns {T | undefined} A random element from the array, or `undefined` if the array is empty.
*
* @example
* const arrayLike: ArrayLike<string> = { 0: 'a', 1: 'b', 2: 'c', length: 3 };
* const result = sample(arrayLike);
* console.log(result); // Output: 'a', 'b', or 'c' (randomly selected)
*/
export function sample<T>(array: ArrayLike<T>): T | undefined;

/**
* Returns a random value from an object.
*
* @template T - The type of values in the object.
* @param {Record<string, T>} obj - The object to sample from.
* @returns {T | undefined} A random value from the object, or `undefined` if the object is empty.
*
* @example
* const obj = { a: 1, b: 2, c: 3 };
* const result = sample(obj);
* console.log(result); // Output: 1, 2, or 3 (randomly selected)
*/
export function sample<T>(obj: Record<string, T>): T | undefined;

/**
* Returns a random element from an array-like object or a regular object.
*
* This function takes an array-like object (such as an array or string) or a regular object,
* and returns a randomly selected element or value. If the collection is empty or invalid, it returns `undefined`.
*
* @template T - The type of elements in the collection.
* @param {ArrayLike<T> | Record<string, T>} collection - The collection to sample from.
* @returns {T | string | undefined} A random element from the collection, or `undefined` if the collection is empty or invalid.
*
* @example
* // Array example
* const array = [1, 2, 3];
* const result = sample(array);
* console.log(result); // Output: 1, 2, or 3 (randomly selected)
*
* // String example
* const str = 'abc';
* const result2 = sample(str);
* console.log(result2); // Output: 'a', 'b', or 'c' (randomly selected)
*
* // Object example
* const obj = { a: 1, b: 2, c: 3 };
* const result3 = sample(obj);
* console.log(result3); // Output: 1, 2, or 3 (randomly selected)
*/
export function sample<T>(collection: ArrayLike<T> | Record<string, T>): T | string | undefined;

/**
* The implementation for the overloaded sample function.
*
* This function takes an array, string, or object and returns a single element selected randomly.
* If the input is empty, or if it's null or undefined, the function returns `undefined`.
*
* @template T - The type of elements in the collection.
* @param {ArrayLike<T> | Record<string, T>} collection - The collection to sample from.
* @returns {T | string | undefined} A random element from the collection, or `undefined` if the collection is empty or invalid.
*/
export function sample<T>(collection: ArrayLike<T> | Record<string, T>): T | string | undefined {
if (collection == null) {
return undefined;
}

if (isArrayLike(collection)) {
return sampleToolkit(Array.from(collection));
}

return sampleToolkit(Object.values(collection));
}
1 change: 1 addition & 0 deletions src/compat/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ export { indexOf } from './array/indexOf.ts';
export { join } from './array/join.ts';
export { last } from './array/last.ts';
export { orderBy } from './array/orderBy.ts';
export { sample } from './array/sample.ts';
export { size } from './array/size.ts';
export { slice } from './array/slice.ts';
export { some } from './array/some.ts';
Expand Down

0 comments on commit be5ba71

Please sign in to comment.