提交:1、导XML格式的CNC 2、NCwriter功能填充
This commit is contained in:
116
src/utils/helper.array.ts
Normal file
116
src/utils/helper.array.ts
Normal file
@@ -0,0 +1,116 @@
|
||||
import { AssignByPath, Resolve, type Paths, type PathValue } from "./helper.lang";
|
||||
|
||||
/**
|
||||
* 将对象数组按指定字段分组,并返回分组结果的数组。
|
||||
*
|
||||
* @template T - 输入数组中对象的类型。
|
||||
* @param data - 要分组的对象数组。
|
||||
* @param fields - 用于分组对象的键(字段)数组。
|
||||
* @param sort - 一个布尔值,指示是否按键对分组结果进行排序。默认为 `true`。
|
||||
* @param separator - 用于连接字段值以形成分组键的字符串。默认为 `'-'`。
|
||||
* @returns 分组结果的数组
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* const data = [
|
||||
* { category: 'A', type: 'X', value: 10 },
|
||||
* { category: 'A', type: 'Y', value: 20 },
|
||||
* { category: 'B', type: 'X', value: 30 },
|
||||
* ];
|
||||
* const grouped = GroupBy(data, ['category', 'type']);
|
||||
* console.log(grouped);
|
||||
* // 输出:
|
||||
* // [
|
||||
* // {
|
||||
* // key: 'A-X',
|
||||
* // keyList: ['A', 'X'],
|
||||
* // value: [{ category: 'A', type: 'X', value: 10 }],
|
||||
* // keyObj: { category: 'A', type: 'X' }
|
||||
* // },
|
||||
* // {
|
||||
* // key: 'A-Y',
|
||||
* // keyList: ['A', 'Y'],
|
||||
* // value: [{ category: 'A', type: 'Y', value: 20 }],
|
||||
* // keyObj: { category: 'A', type: 'Y' }
|
||||
* // },
|
||||
* // {
|
||||
* // key: 'B-X',
|
||||
* // keyList: ['B', 'X'],
|
||||
* // value: [{ category: 'B', type: 'X', value: 30 }],
|
||||
* // keyObj: { category: 'B', type: 'X' }
|
||||
* // }
|
||||
* // ]
|
||||
* ```
|
||||
*/
|
||||
export function GroupBy<T extends object, TKeys extends (Paths<T>)[]>(
|
||||
data: T[],
|
||||
fields: TKeys,
|
||||
sort = true,
|
||||
separator = '-',
|
||||
) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const groupList = {} as any;
|
||||
const groupArray = [] as IGrouping<T, { [Key in TKeys[number]]: PathValue<T, Key> }>[];
|
||||
if (fields.length === 0) return [];
|
||||
for (const item of data) {
|
||||
const keyList = fields.map((field) => Resolve(item, field));
|
||||
const key = keyList.join(separator);
|
||||
groupList[key] = groupList[key] || [];
|
||||
groupList[key].push(item);
|
||||
groupList[key].keyList = keyList;
|
||||
const keyObj = {} as T;
|
||||
fields.forEach((t) => {
|
||||
AssignByPath(keyObj, t, Resolve(item, t) as PathValue<T, typeof t>);
|
||||
});
|
||||
groupList[key].keyObj = keyObj;
|
||||
}
|
||||
for (const key in groupList) {
|
||||
groupArray.push({
|
||||
key,
|
||||
keyList: groupList[key].keyList,
|
||||
value: groupList[key],
|
||||
keyObj: groupList[key].keyObj,
|
||||
});
|
||||
}
|
||||
if (sort)
|
||||
return groupArray.sort(function (a, b) {
|
||||
return a.key.localeCompare(b.key, 'zh-CN', { numeric: true });
|
||||
});
|
||||
else return groupArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将对象数组按指定字段分组,并返回分组结果的数组。
|
||||
*/
|
||||
export interface IGrouping<T, TKeyRecord> {
|
||||
/**
|
||||
* 分组的键,若有多个键,则用连接符连接
|
||||
*/
|
||||
key: string;
|
||||
/**
|
||||
* 分组的键列表
|
||||
*/
|
||||
keyList: unknown[];
|
||||
/**
|
||||
* 分组的对象数组
|
||||
*/
|
||||
value: T[];
|
||||
/**
|
||||
* 分组键对象,其属性名为分组键名,属性值为分组键
|
||||
*/
|
||||
keyObj: TKeyRecord;
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface Array<T> {
|
||||
GroupBy: <TKeys extends (Paths<T>)[]>(
|
||||
fields: TKeys,
|
||||
sort?: boolean,
|
||||
separator?: string,
|
||||
) => Array<IGrouping<T, { [Key in TKeys[number]]: PathValue<T, Key> }>>;
|
||||
}
|
||||
}
|
||||
|
||||
Array.prototype.GroupBy = function (fields, sort, separator) {
|
||||
return GroupBy(this, fields, sort, separator);
|
||||
};
|
Reference in New Issue
Block a user