const people = [
{name: 'ALice', age: 30, sex: 'female'},
{name: 'BOb', age: 25, sex: 'male'},
{name: 'Chartlie', age: 30, sex: 'male'},
{name: 'Diana', age: 25, sex: 'female'},
{name: 'Eva', age: 25, sex: 'female'},
{name: 'Frank', age: 25, sex: 'male'},
{name: 'Grace', age: 20, sex: 'female'}
];
// 初始实现:按年龄分组
const result = {};
for (const item of people) {
const key = item.age;
if (!result[key]) {
result[key] = [];
}
result[key].push(item);
}
上述代码实现了对人员数组按照年龄进行分类。然而,当需求变为按性别或其他字段分组时,就需要重复编写类似的逻辑。例如,若要改为按性别归类,则需调整键值提取方式:
// 按性别分组(修改后的版本)
const result = {};
for (const item of people) {
const key = item.sex;
if (!result[key]) {
result[key] = [];
}
result[key].push(item);
}
这种重复编码显然不够高效。为此,可以封装一个通用的分组函数,使其支持动态指定分组依据。
// 封装基础分组函数
function groupBy(arr, propName) {
const result = {};
for (const item of arr) {
const key = item[propName];
if (!result[key]) {
result[key] = [];
}
result[key].push(item);
}
return result;
}
// 使用示例
const result1 = groupBy(people, 'age');
const result2 = groupBy(people, 'sex');
虽然该函数已具备一定通用性,但面对更复杂的场景仍显不足。比如,数据结构中包含嵌套对象(如 address: {province: "河南", city: "开封"}),或需要基于多个字段组合分组,甚至根据数值奇偶性进行分类时,简单的属性名传参就无法满足需求了。
为提升灵活性,应将“键值生成”这一过程抽象成一个函数参数,从而让调用者自定义分组逻辑。
// 增强版分组函数:接受键值生成函数
function groupBy(arr, generateKey) {
const result = {};
for (const item of arr) {
const key = generateKey(item);
if (!result[key]) {
result[key] = [];
}
result[key].push(item);
}
return result;
}
// 应用示例:
// 按年龄分组
const result1 = groupBy(people, (item) => item.age);
// 按性别分组
const result2 = groupBy(people, (item) => item.sex);
// 按年龄和性别联合分组
const result3 = groupBy(people, (item) => `${item.age}-${item.sex}`);
不仅如此,该模式还可拓展至非对象数组的场景。例如,处理数字数组并按奇偶性分组:
const arr = [34, 6, 321, 3, 5, 7]; const result4 = groupBy(arr, (item) => item % 2 === 0 ? '偶' : '奇');
通过将分组键的生成方式由固定属性访问升级为可配置函数,groupBy 函数获得了更高的复用性和适应能力,能够应对各种复杂的数据组织需求。
该函数在功能实现上已经没有问题,但在使用体验上仍有优化空间。我们期望它能够支持两种不同的参数传递方式:一种是通过属性名称进行分组,另一种是通过函数逻辑动态生成分组依据。由于参数形式存在两种可能,因此需要引入参数归一化的处理机制来统一调用逻辑。
以下是具体的实现代码:
// 分组函数
function groupBy(arr, generateKey) {
if (typeof generateKey === 'string') {
const propName = generateKey;
generateKey = (item) => item[propName];
}
const result = {};
for (const item of arr) {
const key = generateKey(item);
if (!result[key]) {
result[key] = [];
}
result[key].push(item);
}
return result;
}
接下来展示几种常见的调用场景:
按“年龄”字段进行分组:
const result1 = groupBy(people, 'age');
按“性别”字段进行分组:
const result2 = groupBy(people, 'sex');
按“年龄-性别”组合条件进行分组:
const result3 = groupBy(people, (item) => `${item.age}-${item.sex}`);
当处理的是数字数组时,也可根据特定规则进行分类。例如将数组元素按奇偶性分组:
const arr = [34, 6, 321, 3, 5, 7];
const result4 = groupBy(arr, (item) => item % 2 === 0 ? '偶' : '奇');
通过上述方式,无论传入的是字符串属性名还是自定义函数,都能被统一处理,提升了函数的灵活性与易用性。这种参数归一化的设计模式在工具函数开发中非常实用。


雷达卡


京公网安备 11010802022788号







