如何修改现有函数实现按lastName和gender双属性分组数组对象
如何修改分组函数以支持多属性分组
现有如下用户数组需要分组:
[ { "name": "john", "lastName": "doe", "gender": "male" }, { "name": "jane", "lastName": "doe", "gender": "female" }, { "name": "peter", "lastName": "dickons", "gender": "male" }, { "name": "eva", "lastName": "dickons", "gender": "female" } ]
目前已经实现了按单个属性分组的函数(JavaScript和TypeScript版本如下),现在需要修改函数,让它支持传入lastName和gender两个属性,实现按双属性分组。
现有单属性分组函数
JavaScript版本
const groupByObjectKey = (users, key) => { return users.reduce((rv, x) => { (rv[x[key]] = rv[x[key]] || []).push(x); return rv; }, {}); }; // 使用示例 let users = [/* 上述数组内容 */]; const usersGroupedByLastName = groupByObjectKey(users, "lastName"); console.log(usersGroupedByLastName);
TypeScript版本
interface User { name: string; lastName: string; gender: string; } const groupByObjectKey = (users: User[], key: string): Record<string, User[]> => { return users.reduce((rv, x) => { (rv[x[key]] = rv[x[key]] || []).push(x); return rv; }, {} as Record<string, User[]>); }; // 使用示例 const users: User[] = [/* 上述数组内容 */]; const usersGroupedByLastName = groupByObjectKey(users, "lastName");
修改方案
下面提供两种常用的多属性分组实现方式,你可以根据需求选择:
方案1:使用复合字符串键分组
这种方式把多个属性值拼接成一个字符串作为分组键,实现简单,适合不需要嵌套结构的场景。
修改后的JavaScript函数:
const groupByKeys = (users, keys) => { return users.reduce((rv, x) => { // 用短横线拼接属性值生成复合键,也可以用其他分隔符(比如下划线) const groupKey = keys.map(key => x[key]).join('-'); (rv[groupKey] = rv[groupKey] || []).push(x); return rv; }, {}); }; // 使用示例 const usersGroupedByLastNameAndGender = groupByKeys(users, ["lastName", "gender"]); console.log(usersGroupedByLastNameAndGender);
输出结果:
{ "doe-male": [{"name":"john","lastName":"doe","gender":"male"}], "doe-female": [{"name":"jane","lastName":"doe","gender":"female"}], "dickons-male": [{"name":"peter","lastName":"dickons","gender":"male"}], "dickons-female": [{"name":"eva","lastName":"dickons","gender":"female"}] }
方案2:生成嵌套结构的分组结果
如果希望分组结果是嵌套对象(比如{ 姓氏: { 性别: [用户列表] } }),可以用下面的实现:
修改后的JavaScript函数:
const groupByNestedKeys = (users, keys) => { return users.reduce((rv, x) => { let currentLevel = rv; // 逐层遍历分组键,构建嵌套结构 for (let i = 0; i < keys.length; i++) { const key = keys[i]; const value = x[key]; // 最后一个键直接对应用户数组 if (i === keys.length - 1) { (currentLevel[value] = currentLevel[value] || []).push(x); } else { // 非最后一个键则创建嵌套对象 currentLevel[value] = currentLevel[value] || {}; currentLevel = currentLevel[value]; } } return rv; }, {}); }; // 使用示例 const nestedGroupedUsers = groupByNestedKeys(users, ["lastName", "gender"]); console.log(nestedGroupedUsers);
输出结果:
{ "doe": { "male": [{"name":"john","lastName":"doe","gender":"male"}], "female": [{"name":"jane","lastName":"doe","gender":"female"}] }, "dickons": { "male": [{"name":"peter","lastName":"dickons","gender":"male"}], "female": [{"name":"eva","lastName":"dickons","gender":"female"}] } }
TypeScript版本的多属性分组函数
如果用TypeScript,可以给函数加上泛型,保证类型安全:
复合键版本
interface User { name: string; lastName: string; gender: string; } const groupByKeys = <T extends Record<string, any>>(items: T[], keys: (keyof T)[]): Record<string, T[]> => { return items.reduce((rv, item) => { const groupKey = keys.map(key => item[key]).join('-'); (rv[groupKey] = rv[groupKey] || []).push(item); return rv; }, {} as Record<string, T[]>); }; // 使用示例 const users: User[] = [/* 上述数组内容 */]; const groupedByTwoKeys = groupByKeys(users, ["lastName", "gender"]);
嵌套结构版本
const groupByNestedKeys = <T extends Record<string, any>>(items: T[], keys: (keyof T)[]): any => { return items.reduce((rv, item) => { let currentLevel: any = rv; for (let i = 0; i < keys.length; i++) { const key = keys[i]; const value = item[key]; if (i === keys.length - 1) { (currentLevel[value] = currentLevel[value] || []).push(item); } else { currentLevel[value] = currentLevel[value] || {}; currentLevel = currentLevel[value]; } } return rv; }, {}); }; // 使用示例 const nestedGrouped = groupByNestedKeys(users, ["lastName", "gender"]);
内容的提问来源于stack exchange,提问作者erol_smsr
相关产品推荐
相关产品推荐

