天天看點

代碼小技巧:數組分組實作方式

作者:速學前端

假設我們有一個數組,數組如下:

const people = [
    {name: 'one', age: 30, sex: '男', address: {province: "浙江", city: "杭州"}},
    {name: 'two', age: 23, sex: '男', address: {province: "浙江", city: "杭州"}},
    {name: 'three', age: 30, sex: '女', address: {province: "浙江", city: "杭州"}},
    {name: 'four', age: 23, sex: '男', address: {province: "福建", city: "廈門"}},
    {name: 'five', age: 23, sex: '女', address: {province: "福建", city: "龍岩"}},
    {name: 'six', age: 24, sex: '男', address: {province: "福建", city: "龍岩"}},
];           

我們有一個需求,需要按name屬性進行分組,我們可以按如下實作:

const result = {};
for (let item of people) {
    let key = item.age;
    if (!result[key]) {
        result[key] = []
    }
    result[key].push(item);
}
console.log(result);           

此時result列印出了我們要的結果

{
  '23': [
    { name: 'two', age: 23, sex: '男' },
    { name: 'four', age: 23, sex: '男' },
    { name: 'five', age: 23, sex: '女' }
  ],
  '24': [ { name: 'six', age: 24, sex: '男', address: {} } ],
  '30': [
    { name: 'one', age: 30, sex: '男' },
    { name: 'three', age: 30, sex: '女' }
  ]
}
           

但是需求是會變化的,有一天我們想按sex屬性分組,上面的代碼就不能夠滿足需求了。我們發現當我們想按sex屬性分組時,隻需要将上面代碼的age改為sex就可以

const result = {};
for (let item of people) {
  	//此處是變化的
    let key = item.sex;
    if (!result[key]) {
        result[key] = []
    }
    result[key].push(item);
}
console.log(result);           

我們很容易發現代碼隻有key是不同的,是以我們可以想到封裝一個函數,我們叫這個函數為groupBy

function groupBy(arr, propName) {
    const result = {};
    for (let item of arr) {
        let key = item[propName];
        if (!result[key]) {
            result[key] = []
        }
        result[key].push(item);
    }
    return result;
}

console.log(groupBy(people, 'age'));
console.log(groupBy(people, 'sex'));           

分組其實還有很多情況:

  1. 按嵌套的字段分組
  2. 按組合字段分組,比如:age+sex
  3. 直接按數組元素的奇偶進行分組

可以看到,當加入上述情況後,上面的函數就嘎了。需求本質上是key在變化,是以怎麼獲得key才是問題的關鍵,将上述函數修改

function groupBy(arr, generateKey) {
    const result = {};
    for (let item of arr) {
      //變化的
        let key = generateKey(item);
        if (!result[key]) {
            result[key] = []
        }
        result[key].push(item);
    }
    return result;
}

// 按年齡
console.log(groupBy(people, (item) => item.age));
// 按性别
console.log(groupBy(people, (item) => item.sex));
// 按年齡和性别組合
console.log(groupBy(people, (item) => `${item.sex}-${item.age}`));
// 按嵌套字段
console.log(groupBy(people, (item) => item.address.province));

const arr = [1, 2, 3, 4, 5, 6]
console.log(groupBy(arr, (item) => item % 2 === 0 ? '偶' : '奇'))           

我們将擷取key的方式通過函數傳入,解決了我們的問題。然而這種方式調用起來不太友善,我們希望函數可以有有兩種調用方式:groupBy(people, (item) => item.age)或者groupBy(people, 'age'),這時候我們就可以對參數進行判斷:

function groupBy(arr, generateKey) {
    if (typeof generateKey === 'string') {
        const propName = generateKey;
        generateKey = (item) => item[propName];
    }
    const result = {};
    for (let item of arr) {
        let key = generateKey(item);
        if (!result[key]) {
            result[key] = []
        }
        result[key].push(item);
    }
    return result;
}           

通過判斷generateKey傳入的類型對參數進行處理轉化就可以實作不同的調用方式。

繼續閱讀