let list = [
{ id: 'id_a1', name: 'DuFu', age: 20, sex: 'male' },
{ id: 'id_b2', name: 'LiQingZhao', age: 18, sex: 'female' },
{ id: 'id_c3', name: 'LiBai', age: 26, sex: 'male' },
{ id: 'id_d4', name: 'XinQiJi', age: 30, sex: 'male' },
{ id: 'id_e5', name: 'LinHuiYin', age: 25, sex: 'female' },
{ id: 'id_f6', name: 'MouMouMou', age: 18, sex: 'female' },
{ id: 'id_g7', name: 'HeZhiZhang', age: 26, sex: 'male' }
],
numArr = [1, 28, 2, 29, 5, 30, 6, 37, 3, 12, 36, 8, 52, 9, 51, 5, 65];
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; } console.log(groupBy(list, 'age')); // {18: Array(2), 20: Array(1), 25: Array(1), 26: Array(2), 30: Array(1)} console.log(groupBy(list, 'sex')); // {male: Array(4), female: Array(3)}
这个版本相信大家已看就懂,不多做解释。
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; } console.log(groupBy(list, item => item.age)); // {18: Array(2), 20: Array(1), 25: Array(1), 26: Array(2), 30: Array(1)} console.log(groupBy(list, item => item.sex)); // {male: Array(4), female: Array(3)} console.log(groupBy(list, item => `${item.sex}_${item.age}`)); // {male_20: Array(1), female_18: Array(2), male_26: Array(2), male_30: Array(1), female_25: Array(1)} console.log(groupBy(numArr, item => item % 2 === 0 ? 'even' : 'odd')); // {odd: Array(9), even: Array(8)}
仔细观察就不难发现,第二个参数已经不再是普通的字符串了。而是从字符串转变为函数,函数通过调用,把最终分组的形式和依据转交给了调用者。调用者可以根据自己的需求编写传入的分组依据。
function groupBy(arr, generateKey) { // 参数归一化(一) // if (typeof generateKey === 'string') generateKey = (item) => item[generateKey]; // 参数归一化(二) if (typeof generateKey === 'string') { const keyPropertyName = generateKey; generateKey = (item) => item[keyPropertyName]; } const result = {}; for (const item of arr) { const key = generateKey(item); if (!result[key]) result[key] = []; result[key].push(item); } return result; } console.log(groupBy(list, item => item.age)); // {18: Array(2), 20: Array(1), 25: Array(1), 26: Array(2), 30: Array(1)} console.log(groupBy(list, item => item.sex)); // {male: Array(4), female: Array(3)} console.log(groupBy(list, item => `${item.sex}_${item.age}`)); // {male_20: Array(1), female_18: Array(2), male_26: Array(2), male_30: Array(1), female_25: Array(1)} console.log(groupBy(numArr, item => item % 2 === 0 ? 'even' : 'odd')); // {odd: Array(9), even: Array(8)} console.log(groupBy(list, 'age')); // {18: Array(2), 20: Array(1), 25: Array(1), 26: Array(2), 30: Array(1)} console.log(groupBy(list, 'sex')); // {male: Array(4), female: Array(3)}
这里主要解释一下参数归一化,意思就是把不同的参数类型转为同一种数据类型。这里是把字符串类型的参数转为函数类型的参数。
参数归一化的第一种方式存在问题,所以使用了第二种方式实现参数归一化。
存在的问题
generateKey的值不会在函数中正确解析。这是因为在箭头函数中,它会捕获最外层的generateKey变量,而不是按照意图解析字符串并使用它作为属性名称。if (typeof generateKey === 'string') generateKey = (item) => item[generateKey];
if (typeof generateKey === 'string') { const keyPropertyName = generateKey; generateKey = (item) => item[keyPropertyName]; }