Skip to content

Commit

Permalink
Merge pull request chenbimo#15 from chenbimo/main
Browse files Browse the repository at this point in the history
merge
  • Loading branch information
ForeverGuo authored Aug 12, 2024
2 parents 278b544 + 2e51041 commit 44678e4
Show file tree
Hide file tree
Showing 30 changed files with 955 additions and 24 deletions.
2 changes: 2 additions & 0 deletions .npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
registry=https://registry.npmmirror.com
# registry=https://registry.npmjs.org
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ console.log(validNumber('1.2.')); // 1.20
2. fork本仓库main分支。
3. 拉取fork后的仓库。
4. 修改代码。
5. push代码到本仓库
5. push代码到fork后的仓库
6. 发起pull request。
7. 等待笔者验证与合并。

Expand Down
18 changes: 18 additions & 0 deletions lib/array/max.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/**
* @alias yd_array_max
* @category array
* @param {Array} array - 输入的数组。
* @returns {number} - 数组中的最大值。
* @author penn <https://github.com/penn201500>
* @example
* console.log(arrayMax([1, 2, 3, 4, 5]))
* // 输出: 5
* @description 计算数组中的最大值。
*/
export default (array) => {
try {
return Math.max(...array);
} catch (error) {
throw new TypeError('An error occurred: ' + error.message);
}
};
25 changes: 25 additions & 0 deletions lib/array/max.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { it, expect, describe } from 'vitest';
import yd_array_max from './max.js';

describe('yd_array_max', () => {
it('should return the max value in the array', () => {
const arr = [1, 2, 3, 4, 5];
const result = yd_array_max(arr);
expect(result).toBe(5);
});

it('should return NaN if the array contains non-number element', () => {
const arr1 = [6, 2, 3, '1', 5];
const arr2 = [1, 2, 3, 'a', 5];
const result1 = yd_array_max(arr1);
const result2 = yd_array_max(arr2);
expect(result1).toBe(6);
expect(result2).toBeNaN();
});

it('should return Infinity if the array is empty', () => {
const arr = [];
const result = yd_array_max(arr);
expect(result).toBe(-Infinity);
});
});
32 changes: 32 additions & 0 deletions lib/array/maxBy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/**
* 根据属性键或访问器函数找到数组中的最大元素
* @author Amonduul <https://amonduul.vercel.app>
* @alias yd_array_maxBy
* @category array
* @param {Array} array - 要搜索的数组
* @param {Function|string} iteratee - 用于提取比较值的函数或属性键
* @returns {*} 返回数组中具有最大值的元素
* @throws {Error} 如果提供的数组为空或 iteratee 不是函数或字符串
*/
export default (array, iteratee) => {
if (!Array.isArray(array) || array.length === 0) {
throw new Error('First argument must be a non-empty array.');
}

if (typeof iteratee !== 'function' && typeof iteratee !== 'string') {
throw new Error('Second argument must be a function or a string.');
}

let maxElement = array[0];
let maxValue = typeof iteratee === 'function' ? iteratee(maxElement) : maxElement[iteratee];

for (const element of array) {
const value = typeof iteratee === 'function' ? iteratee(element) : element[iteratee];
if (value > maxValue) {
maxElement = element;
maxValue = value;
}
}

return maxElement;
};
34 changes: 34 additions & 0 deletions lib/array/maxBy.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { describe, it, expect } from 'vitest';
import yd_array_maxBy from './maxBy.js';

describe('yd_array_maxBy', () => {
it('should find the element with the maximum value in an array', () => {
const array = [
{ name: 'Alice', age: 25 },
{ name: 'Bob', age: 30 },
{ name: 'Charlie', age: 20 }
];

const result = yd_array_maxBy(array, 'age');
expect(result).toEqual({ name: 'Bob', age: 30 });
});

it('should accept a function as the iteratee', () => {
const array = [
{ name: 'Alice', age: 25 },
{ name: 'Bob', age: 30 },
{ name: 'Charlie', age: 20 }
];

const result = yd_array_maxBy(array, (item) => item.age);
expect(result).toEqual({ name: 'Bob', age: 30 });
});

it('should throw an error if the array is empty', () => {
expect(() => yd_array_maxBy([], 'age')).toThrow('First argument must be a non-empty array.');
});

it('should throw an error if the iteratee is not a function or a string', () => {
expect(() => yd_array_maxBy([{ a: 1 }, { a: 2 }], 123)).toThrow('Second argument must be a function or a string.');
});
});
22 changes: 22 additions & 0 deletions lib/array/merge.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/**
* 合并多个数组并返回它们的并集
* @author Amonduul <https://amonduul.vercel.app>
* @category array
* @alias yd_array_merge
* @param { Array } ...arrays - 可变数量的数组参数
* @returns { Array } 所有数组的并集
* @throws { Error } 如果任何一个参数不是数组
*/
export default (...arrays) => {
// 检查每个参数是否都是数组
if (!arrays.every(Array.isArray)) {
throw new Error('All arguments must be arrays.');
}
const unionSet = new Set();
arrays.forEach((array) => {
array.forEach((item) => {
unionSet.add(item);
});
});
return Array.from(unionSet);
};
16 changes: 16 additions & 0 deletions lib/array/merge.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { describe, it, expect } from 'vitest';
import yd_array_merge from './merge.js';

describe('yd_array_merge', () => {
it('should merge multiple arrays and return their union', () => {
const arr1 = [1, 2, 3];
const arr2 = [3, 4, 5];
const arr3 = [5, 6, 7];

expect(yd_array_merge(arr1, arr2, arr3)).toEqual([1, 2, 3, 4, 5, 6, 7]);
});

it('should throw an error if any argument is not an array', () => {
expect(() => yd_array_merge([1, 2], 'foo')).toThrow('All arguments must be arrays.');
});
});
18 changes: 18 additions & 0 deletions lib/array/min.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/**
* @alias yd_array_min
* @category array
* @param {Array} array - 输入的数组。
* @returns {number} - 数组中的最小值。
* @author penn <https://github.com/penn201500>
* @example
* console.log(arrayMin([1, 2, 3, 4, 5]))
* // 输出: 1
* @description 计算数组中的最小值
*/
export default (array) => {
try {
return Math.min(...array);
} catch (error) {
throw new TypeError('An error occurred: ' + error.message);
}
};
25 changes: 25 additions & 0 deletions lib/array/min.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { it, expect, describe } from 'vitest';
import yd_array_min from './min.js';

describe('yd_array_min', () => {
it('should return the min value in the array', () => {
const arr = [1, 2, 3, 4, 5];
const result = yd_array_min(arr);
expect(result).toBe(1);
});

it('should return NaN if the array contains non-number element', () => {
const arr1 = [6, 2, 3, '1', 5];
const arr2 = [1, 2, 3, 'a', 5];
const result1 = yd_array_min(arr1);
const result2 = yd_array_min(arr2);
expect(result1).toBe(1);
expect(result2).toBeNaN();
});

it('should return Infinity if the array is empty', () => {
const arr = [];
const result = yd_array_min(arr);
expect(result).toBe(Infinity);
});
});
43 changes: 43 additions & 0 deletions lib/array/swapElements.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/**
* @alias yd_array_swapElements
* @category array
* @param {Array} array - 需要交换元素的数组。
* @param {...Array} pairs - 每个 element 对由两个索引组成,表示数组中要交换的元素位置。
* @returns {void} - 该函数会直接修改输入的数组,不返回任何值。
* @author penn <https://github.com/penn201500>
* @summary 该函数接收一个数组和 1或多 个索引对,交换数组中每对索引指定的位置的元素。函数直接修改输入的数组,因此不会返回新的数组。如果索引对中的两个索引相同,该索引处的元素保持不变。
* @example
* const numbers = [1, 2, 3, 4, 5];
* yd_array_swapElements(numbers, [0, 3], [1, 4]);
* console.log(numbers); // [4, 5, 3, 1, 2]
*
* @description 交换数组中元素对的位置。
*/
export default (array, ...pairs) => {
// 检查 array 是否为数组
if (!Array.isArray(array)) {
throw new TypeError('第一个参数必须是一个数组');
}

// 检查每对索引是否为合法数组和有效的数字
pairs.forEach((pair) => {
if (!Array.isArray(pair) || pair.length !== 2) {
throw new TypeError('每个索引对必须是一个包含两个数字的数组');
}

const [index1, index2] = pair;

if (typeof index1 !== 'number' || typeof index2 !== 'number') {
throw new TypeError('索引必须是数字');
}

if (index1 < 0 || index1 >= array.length || index2 < 0 || index2 >= array.length) {
throw new RangeError('索引超出数组的范围');
}
});

// 执行交换
pairs.forEach(([index1, index2]) => {
[array[index1], array[index2]] = [array[index2], array[index1]];
});
};
42 changes: 42 additions & 0 deletions lib/array/swapElements.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { it, expect, describe } from 'vitest';
import yd_array_swapElements from './swapElements.js';

describe('yd_array_swapElements', () => {
it('should swap elements correctly', () => {
const numbers = [1, 2, 3, 4, 5];
yd_array_swapElements(numbers, [0, 3], [1, 4]);
expect(numbers).toEqual([4, 5, 3, 1, 2]);
});

it('should handle swaps with the same index', () => {
const numbers = [1, 2, 3, 4, 5];
yd_array_swapElements(numbers, [1, 1]);
expect(numbers).toEqual([1, 2, 3, 4, 5]);
});

it('should handle no swap', () => {
const numbers = [1, 2, 3, 4, 5];
yd_array_swapElements(numbers);
expect(numbers).toEqual([1, 2, 3, 4, 5]);
});

it('should throw error if first argument is not an array', () => {
expect(() => yd_array_swapElements('abc', [1, 2]).toThrow(TypeError));
expect(() => yd_array_swapElements('abc', [1, 2]).toThrow('第一个参数必须是一个数组'));
});

it('should throw error if swap pair is not an array', () => {
expect(() => yd_array_swapElements([1, 2, 3, 4, 5], (1, 2)).toThrow(TypeError));
expect(() => yd_array_swapElements([1, 2, 3, 4, 5], (1, 2)).toThrow('每个索引对必须是一个包含两个数字的数组'));
});

it('should throw error if swap pair is not an array consist of 2 numbers', () => {
expect(() => yd_array_swapElements([1, 2, 3, 4, 5], [1, 'a']).toThrow(TypeError));
expect(() => yd_array_swapElements([], [1, 'a']).toThrow('索引必须是数字'));
});

it('should throw error if swap pair index out of array bounds', () => {
expect(() => yd_array_swapElements([1, 2, 3, 4, 5], [1, 6]).toThrow(TypeError));
expect(() => yd_array_swapElements([], [1, 6]).toThrow('索引超出数组的范围'));
});
});
22 changes: 22 additions & 0 deletions lib/array/toMapByKey.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/**
* 根据某个键的值将数组转换为 Map 对象
* @author Amonduul <https://amonduul.vercel.app>
* @category array
* @alias yd_array_toMapByKey
* @param { Array } array 数组
* @param { any } keyName 键名,确保该键名对应的值是数组项的唯一标识,否则会被覆盖
* @returns { Map } 返回一个 Map 对
*/
export default (array, keyName) => {
if (!keyName) {
throw new Error('keyName is required');
}
const map = new Map();
for (const item of array) {
// 确保 item 是一个对象且包含 keyName 键
if (item && typeof item === 'object' && keyName in item) {
map.set(item[keyName], item);
}
}
return map;
};
66 changes: 66 additions & 0 deletions lib/array/toMapByKey.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { describe, it, expect } from 'vitest';
import yd_array_toMapByKey from './toMapByKey.js';

describe('yd_array_toMapByKey', () => {
it('默认单测', () => {
const arr = [
{
id: 1,
name: 'a'
},
{
id: 2,
name: 'b'
}
];
const map = yd_array_toMapByKey(arr, 'id');
expect(map.get(1)).toEqual({
id: 1,
name: 'a'
});
expect(map.get(2)).toEqual({
id: 2,
name: 'b'
});
});
it('空数组', () => {
const arr = [];
const map = yd_array_toMapByKey(arr, 'id');
expect(map.size).toBe(0);
});
it('非数组', () => {
const arr = 'a';
const map = yd_array_toMapByKey(arr, 'id');
expect(map.size).toBe(0);
});
it('数组元素不是对象', () => {
const arr = [1, 2];
const map = yd_array_toMapByKey(arr, 'id');
expect(map.size).toBe(0);
});
it('数组元素不包含 keyName 键', () => {
const arr = [
{
name: 'a'
},
{
name: 'b'
}
];
const map = yd_array_toMapByKey(arr, 'id');
expect(map.size).toBe(0);
});
it('keyName 为空', () => {
const arr = [
{
id: 1,
name: 'a'
},
{
id: 2,
name: 'b'
}
];
expect(() => yd_array_toMapByKey(arr)).toThrow('keyName is required');
});
});
Loading

0 comments on commit 44678e4

Please sign in to comment.