ronantakizawa/codereview-bench huggingface dataset:
Repository: toss/es-toolkit
File: src/compat/array/sample.ts (TypeScript)

Code before:
import { sample as sampleToolkit } from '../../array/sample';
import { isArrayLike } from '../predicate/isArrayLike';

/**
 * 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)

Review comment (suggestion):
```suggestion
import { sample as sampleToolkit } from '../../array/sample.ts';
import { isArrayLike } from '../predicate/isArrayLike.ts';
```

Code after:
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)
Repository: toss/es-toolkit
File: src/compat/array/sample.ts (TypeScript)

Code before:
 * 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(collection as readonly T[]);
  }

  const values = Object.values(collection);
  return values.length ? sampleToolkit(values) : undefined;
}


Review comment (suggestion):
```suggestion
    return sampleToolkit(Array.from(collection));
```

Code after:
 * 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));
}
Repository: toss/es-toolkit
File: src/math/median.ts (TypeScript)

Code before:
 * If the array has an odd number of elements, it returns the middle element.
 * If the array has an even number of elements, it returns the average of the two middle elements.
 *
 * @param {number[]} nums - An array of numbers to calculate the median.
 * @returns {number} The median of all the numbers in the array.
 *
 * @example
 * const arrayWithOddNumberOfElements = [1, 2, 3, 4, 5];
 * const result = median(arrayWithOddNumberOfElements);
 * // result will be 3
 *
 * @example
 * const arrayWithEvenNumberOfElements = [1, 2, 3, 4];
 * const result = median(arrayWithEvenNumberOfElements);
 * // result will be 2.5
 */
export function median(nums: readonly number[]): number {
  if (nums.length === 0) {
    return NaN;
  }

  const sorted = [...nums].sort((a, b) => a - b);
  const middleIndex = Math.floor(sorted.length / 2);

  if (sorted.length % 2 === 0) {
    return mean([sorted[middleIndex - 1], sorted[middleIndex]]);
  } else {
    return sorted[middleIndex];
  }
}


Review comment (suggestion):
```suggestion
    return (sorted[middleIndex - 1] + sorted[middleIndex])/ 2;
```

Since we are simply getting the mean of two numbers, we might directly calculate the average here.

Code after:
 * If the array has an odd number of elements, the median is the middle value.
 * If the array has an even number of elements, it returns the average of the two middle values.
 *
 * If the array is empty, this function returns `NaN`.
 *
 * @param {number[]} nums - An array of numbers to calculate the median.
 * @returns {number} The median of all the numbers in the array.
 *
 * @example
 * const arrayWithOddNumberOfElements = [1, 2, 3, 4, 5];
 * const result = median(arrayWithOddNumberOfElements);
 * // result will be 3
 *
 * @example
 * const arrayWithEvenNumberOfElements = [1, 2, 3, 4];
 * const result = median(arrayWithEvenNumberOfElements);
 * // result will be 2.5
 */
export function median(nums: readonly number[]): number {
  if (nums.length === 0) {
    return NaN;
  }

  const sorted = nums.slice().sort((a, b) => a - b);
  const middleIndex = Math.floor(sorted.length / 2);

  if (sorted.length % 2 === 0) {
    return (sorted[middleIndex - 1] + sorted[middleIndex]) / 2;
  } else {
    return sorted[middleIndex];
  }
}
Repository: toss/es-toolkit
File: src/compat/array/union.ts (TypeScript)

Code before:
 * @example
 * // Returns [2, 1]
 * union([2], [1, 2]);
 *
 * @example
 * // Returns [2, 1, 3]
 * union([2], [1, 2], [2, 3]);
 *
 * @example
 * // Returns [1, 3, 2, [5], [4]] (does not deeply flatten nested arrays)
 * union([1, 3, 2], [1, [5]], [2, [4]]);
 *
 * @example
 * // Returns [0, 2, 1] (ignores non-array values like 3 and { '0': 1 })
 * union([0], 3, { '0': 1 }, null, [2, 1]);
 * @example
 * // Returns [0, 'a', 2, 1] (treats array-like object { 0: 'a', length: 1 } as a valid array)
 * union([0], { 0: 'a', length: 1 }, [2, 1]);
 */
export const union = rest(function <T>(arrays: Array<ArrayLike<T> | null | undefined>): T[] {
  const validArrays = arrays.filter(isArrayLikeObject);

  const flattened = flatten(validArrays, 1);

  return uniq(flattened) as T[];
});


Review comment (suggestion):
```suggestion
export function union<T>(...arrays: Array<ArrayLike<T> | null | undefined>): T[] {
  const validArrays = arrays.filter(isArrayLikeObject);

  const flattened = flatten(validArrays, 1);

  return uniq(flattened) as T[];
};
```

Code after:
 * // Returns [2, 1]
 * union([2], [1, 2]);
 *
 * @example
 * // Returns [2, 1, 3]
 * union([2], [1, 2], [2, 3]);
 *
 * @example
 * // Returns [1, 3, 2, [5], [4]] (does not deeply flatten nested arrays)
 * union([1, 3, 2], [1, [5]], [2, [4]]);
 *
 * @example
 * // Returns [0, 2, 1] (ignores non-array values like 3 and { '0': 1 })
 * union([0], 3, { '0': 1 }, null, [2, 1]);
 * @example
 * // Returns [0, 'a', 2, 1] (treats array-like object { 0: 'a', length: 1 } as a valid array)
 * union([0], { 0: 'a', length: 1 }, [2, 1]);
 */
export function union<T>(...arrays: Array<ArrayLike<T> | null | undefined>): T[] {
  const validArrays = arrays.filter(isArrayLikeObject);

  const flattened = flatten(validArrays, 1);

  return uniq(flattened) as T[];
}
Repository: toss/es-toolkit
File: src/object/mapKeys.ts (TypeScript)

Code before:
/**
 * Creates a new object with the same values as the given object, but with keys generated
 * by running each own enumerable property of the object through the iteratee function.
 *
 * @template T - The type of the object.
 * @template K1 - The type of the keys in the object.
 * @template K2 - The type of the new keys generated by the iteratee function.
 *
 * @param {T} object - The object to iterate over.
 * @param {(value: T[K1], key: K1, object: T) => K2} getNewKey - The function invoked per own enumerable property.
 * @returns {Record<K2, T[K1]>} - Returns the new mapped object.
 *
 * @example
 * // Example usage:
 * const obj = { a: 1, b: 2 };
 * const result = mapKeys(obj, (value, key) => key + value);
 * console.log(result); // { a1: 1, b2: 2 }
 */
export function mapKeys<T extends object, K1 extends keyof T, K2 extends PropertyKey>(
  object: T,
  getNewKey: (value: T[K1], key: K1, object: T) => K2
): Record<K2, T[K1]> {
  const result = {} as Record<K2, T[K1]>;
  const keys = Object.keys(object);

  for (let i = 0; i < keys.length; i++) {
    const key = keys[i] as K1;
    const value = object[key];

    result[getNewKey(value, key, object)] = value as any;
  }

  return result;
}


Review comment (suggestion):
I don't know why there is a `K1` type that extends `keyof T`.

Since there is no reason to extend `keyof T`, we can just use `keyof T`

Code after:
/**
 * Creates a new object with the same values as the given object, but with keys generated
 * by running each own enumerable property of the object through the iteratee function.
 *
 * @template T - The type of the object.
 * @template K - The type of the new keys generated by the iteratee function.
 *
 * @param {T} object - The object to iterate over.
 * @param {(value: T[keyof T], key: keyof T, object: T) => K} getNewKey - The function invoked per own enumerable property.
 * @returns {Record<K, T[keyof T]>} - Returns the new mapped object.
 *
 * @example
 * // Example usage:
 * const obj = { a: 1, b: 2 };
 * const result = mapKeys(obj, (value, key) => key + value);
 * console.log(result); // { a1: 1, b2: 2 }
 */
export function mapKeys<T extends Record<PropertyKey, any>, K extends PropertyKey>(
  object: T,
  getNewKey: (value: T[keyof T], key: keyof T, object: T) => K
): Record<K, T[keyof T]> {
  const result = {} as Record<K, T[keyof T]>;
  const keys = Object.keys(object) as Array<keyof T>;

  for (let i = 0; i < keys.length; i++) {
    const key = keys[i];
    const value = object[key];

    result[getNewKey(value, key, object)] = value as any;
  }

  return result;
}
Repository: toss/es-toolkit
File: src/array/at.ts (TypeScript)

Code before:
 * Retrieves elements from an array at the specified indices.
 *
 * This function supports negative indices, which count from the end of the array.
 *
 * @template T
 * @param {readonly T[]} arr - The array to retrieve elements from.
 * @param {number[]} indices - An array of indices specifying the positions of elements to retrieve.
 * @returns {Array<T | undefined>} A new array containing the elements at the specified indices.
 *
 * @example
 * const numbers = [10, 20, 30, 40, 50];
 * const result = at(numbers, [1, 3, 4]);
 * console.log(result); // [20, 40, 50]
 */
export function at<T>(arr: readonly T[], indices: number[]): Array<T | undefined> {
  const result = new Array<T | undefined>(indices.length);
  const length = arr.length;

  for (let i = 0; i < indices.length; i++) {
    let index = indices[i];

    if (index < 0) {
      index += length;
    }

    result[i] = index >= 0 && index < length && Number.isInteger(index) ? arr[index] : undefined;
  }

  return result;
}


Review comment (performance):
Since the `at` function we're working with isn't the compatibility version, I think we should follow the behavior of the native `Array#at(...)` method. 

Otherwise, it could be confusing, because `at(arr, indices)` would behave differently from `indices.map(index => arr.at(index))`. 

I do appreciate the performance benefits, though.

What do you think?


Code after:
 * Retrieves elements from an array at the specified indices.
 *
 * This function supports negative indices, which count from the end of the array.
 *
 * @template T
 * @param {readonly T[]} arr - The array to retrieve elements from.
 * @param {number[]} indices - An array of indices specifying the positions of elements to retrieve.
 * @returns {Array<T | undefined>} A new array containing the elements at the specified indices.
 *
 * @example
 * const numbers = [10, 20, 30, 40, 50];
 * const result = at(numbers, [1, 3, 4]);
 * console.log(result); // [20, 40, 50]
 */
export function at<T>(arr: readonly T[], indices: number[]): Array<T | undefined> {
  const result = new Array<T | undefined>(indices.length);
  const length = arr.length;

  for (let i = 0; i < indices.length; i++) {
    let index = indices[i];

    index = Number.isInteger(index) ? index : Math.trunc(index) || 0;

    if (index < 0) {
      index += length;
    }

    result[i] = arr[index];
  }

  return result;
}
Repository: toss/es-toolkit
File: src/compat/string/trim.ts (TypeScript)

Code before:
 *
 * @param {string} str - The string from which leading and trailing characters will be trimmed.
 * @param {string | string[]} chars - The character(s) to remove from the end of the string. Defaults to `" "`.
 * @returns {string} - The resulting string after the specified leading and trailing characters have been removed.
 *
 * @example
 * trim("  hello  "); // "hello"
 * trim("--hello--", "-"); // "hello"
 * trim("##hello##", ["#", "o"]); // "hell"
 */
export function trim(str: string, chars?: string | string[], guard?: unknown): string {
  if (str == null) {
    return '';
  }

  if (guard != null || chars == null) {
    return str.toString().trim();
  }

  switch (typeof chars) {
    case 'string': {
      return trimToolkit(str, chars.toString().split(''));
    }
    case 'object': {
      if (Array.isArray(chars)) {
        return trimToolkit(str, flatten(chars.map(x => x.toString().split(''))));
      } else {
        return trimToolkit(str, (chars as any).toString().split(''));
      }
    }
  }
}


Review comment (suggestion):
```suggestion
        return trimToolkit(str, chars.flatMap(x => x.toString().split('')));
```

Code after:
 * @param {string} str - The string from which leading and trailing characters will be trimmed.
 * @param {string | string[]} chars - The character(s) to remove from the end of the string. Defaults to `" "`.
 * @returns {string} - The resulting string after the specified leading and trailing characters have been removed.
 *
 * @example
 * trim("  hello  "); // "hello"
 * trim("--hello--", "-"); // "hello"
 * trim("##hello##", ["#", "o"]); // "hell"
 */
export function trim(str: string, chars?: string | string[], guard?: unknown): string {
  if (str == null) {
    return '';
  }

  if (guard != null || chars == null) {
    return str.toString().trim();
  }

  switch (typeof chars) {
    case 'string': {
      return trimToolkit(str, chars.toString().split(''));
    }
    case 'object': {
      if (Array.isArray(chars)) {
        return trimToolkit(
          str,
          chars.flatMap(x => x.toString().split(''))
        );
      } else {
        return trimToolkit(str, (chars as any).toString().split(''));
      }
    }
  }
}
Repository: toss/es-toolkit
File: src/compat/util/toArray.ts (TypeScript)

Code before:
import { isArrayLike } from '../predicate/isArrayLike';
import { isMap } from '../predicate/isMap';

/**
 * Converts a value to an array.
 *
 * @param {unknown} value - The value to convert.
 * @returns {any[]} Returns the converted array.
 *
 * @example
 * toArray({ 'a': 1, 'b': 2 }) // => returns [1,2]
 * toArray('abc') // => returns ['a', 'b', 'c']
 * toArray(1) // => returns []
 * toArray(null) // => returns []
 */

export function toArray(value?: unknown): any[] {
  if (value == null || typeof value === 'number' || typeof value === 'boolean') {
    return [];
  }

  if (isArrayLike(value) || isMap(value)) {
    return Array.from(value);
  }

  if (typeof value === 'string') {
    return value.split('');
  }

  if (typeof value === 'object') {
    return Object.values(value);
  }

  return [];
}


Review comment (refactor):
```suggestion
  if (value == null) {
```

We might simplify the condition here.

Code after:
import { isArrayLike } from '../predicate/isArrayLike';
import { isMap } from '../predicate/isMap';

/**
 * Converts a value to an array.
 *
 * @param {unknown} value - The value to convert.
 * @returns {any[]} Returns the converted array.
 *
 * @example
 * toArray({ 'a': 1, 'b': 2 }) // => returns [1,2]
 * toArray('abc') // => returns ['a', 'b', 'c']
 * toArray(1) // => returns []
 * toArray(null) // => returns []
 */

export function toArray(value?: unknown): any[] {
  if (value == null) {
    return [];
  }

  if (isArrayLike(value) || isMap(value)) {
    return Array.from(value);
  }

  if (typeof value === 'string') {
    return value.split('');
  }

  if (typeof value === 'object') {
    return Object.values(value);
  }

  return [];
}
Repository: toss/es-toolkit
File: src/compat/array/sortedLastIndexBy.spec.ts (TypeScript)

Code before:
import { describe, expect, it } from 'vitest';
import { sortedLastIndexBy } from './sortedLastIndexBy';

describe('sortedLastIndexBy', () => {
  it('should provide correct `iteratee` arguments', () => {
    let args: unknown[];

    sortedLastIndexBy([30, 50], 40, function (value) {
      args = args || [value];
    });
    // @ts-expect-error Variable 'args' is used before being assigned.ts(2454)
    expect(args).toEqual([40]);
  });

  it('should work with `_.property` shorthands', () => {
    const objects = [{ x: 30 }, { x: 50 }];
    const actual = sortedLastIndexBy(objects, { x: 40 }, v => v.x);

    expect(actual).toBe(1);
  });

  it('should avoid calling iteratee when length is 0', () => {
    const objects: Array<{ x: number }> = [];
    const actual = sortedLastIndexBy(objects, { x: 50 }, () => {
      throw new Error('Iteratee should not be called');
    });

    expect(actual).toBe(0);
  });

  it('should support arrays larger than `MAX_ARRAY_LENGTH / 2`', () => {
    const MAX_ARRAY_LENGTH = 4294967295;
    const MAX_ARRAY_INDEX = MAX_ARRAY_LENGTH - 1;
    const testLengths = [Math.ceil(MAX_ARRAY_LENGTH / 2), MAX_ARRAY_LENGTH];

    testLengths.forEach(length => {
      const array: number[] = [];
      const values = [MAX_ARRAY_LENGTH, NaN, undefined];

      array.length = length;

      values.forEach(value => {

Review comment (suggestion):
Test case misses Lodash's string shorthand pattern. Current test only uses function iteratee `v => v.x` while Lodash tests with string shorthand `'x'`.

Please add test for string shorthand to ensure full compatibility 🙏 

Code after:
import { describe, expect, it } from 'vitest';
import { sortedLastIndexBy } from './sortedLastIndexBy';

describe('sortedLastIndexBy', () => {
  it('should provide correct `iteratee` arguments', () => {
    let args: unknown[];

    sortedLastIndexBy([30, 50], 40, function (value) {
      args = args || [value];
    });
    // @ts-expect-error Variable 'args' is used before being assigned.ts(2454)
    expect(args).toEqual([40]);
  });

  it('should work with `_.property` shorthands', () => {
    const objects = [{ x: 30 }, { x: 50 }];
    const actual = sortedLastIndexBy(objects, { x: 40 }, 'x');

    expect(actual).toBe(1);
  });

  it('should avoid calling iteratee when length is 0', () => {
    const objects: Array<{ x: number }> = [];
    const actual = sortedLastIndexBy(objects, { x: 50 }, () => {
      throw new Error('Iteratee should not be called');
    });

    expect(actual).toBe(0);
  });

  it('should support arrays larger than `MAX_ARRAY_LENGTH / 2`', () => {
    const MAX_ARRAY_LENGTH = 4294967295;
    const MAX_ARRAY_INDEX = MAX_ARRAY_LENGTH - 1;
    const testLengths = [Math.ceil(MAX_ARRAY_LENGTH / 2), MAX_ARRAY_LENGTH];

    testLengths.forEach(length => {
      const array: number[] = [];
      const values = [MAX_ARRAY_LENGTH, NaN, undefined];

      array.length = length;

      values.forEach(value => {
Repository: toss/es-toolkit
File: src/compat/array/sortedLastIndex.spec.ts (TypeScript)

Code before:
import { describe, expect, it } from 'vitest';
import { sortBy } from './sortBy.ts';
import { sortedLastIndex } from './sortedLastIndex.ts';

describe('sortedIndex', () => {
  it(`should return the correct insert index`, () => {
    const array = [30, 50];
    const values = [30, 40, 50];
    const expected = [1, 1, 2];

    const actual = values.map(value => sortedLastIndex(array, value));

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

  it(`should work with an array of strings`, () => {
    const array = ['a', 'c'];
    const values = ['a', 'b', 'c'];
    const expected = [1, 1, 2];

    const actual = values.map(value => sortedLastIndex(array, value));

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

  it(`should handle nullish 'array' and a 'value'`, () => {
    const values = [null, undefined];
    const expected = values.map(() => [0, 0, 0]);

    const actual = values.map(array => [

Review comment (suggestion):
```suggestion
describe('sortedLastIndex', () => {
```

Code after:
import { describe, expect, it } from 'vitest';
import { sortBy } from './sortBy.ts';
import { sortedLastIndex } from './sortedLastIndex.ts';

describe('sortedLastIndex', () => {
  it(`should return the correct insert index`, () => {
    const array = [30, 50];
    const values = [30, 40, 50];
    const expected = [1, 1, 2];

    const actual = values.map(value => sortedLastIndex(array, value));

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

  it(`should work with an array of strings`, () => {
    const array = ['a', 'c'];
    const values = ['a', 'b', 'c'];
    const expected = [1, 1, 2];

    const actual = values.map(value => sortedLastIndex(array, value));

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

  it(`should handle nullish 'array' and a 'value'`, () => {
    const values = [null, undefined];
    const expected = values.map(() => [0, 0, 0]);

    const actual = values.map(array => [