iT邦幫忙

2023 iThome 鐵人賽

DAY 9
0

嗨大家好,我是Eric ~ 在程式開發過程中,陣列分組是一個常見但容易被忽視的需求,不論是依照單一屬性,還是更複雜的條件進行分組,一個具有靈活性和可用性的分組函數能夠大大提升我們的開發效率。今天我們就來一起來看看如何實現一個既通用又靈活的陣列分組函數吧!

首先,假設我們有這樣一個陣列,包含多個人物的基本資料:

const people = [
  { name: 'Wes', age: 1988, sex: 'female' },
  { name: 'Will', age: 1977, sex: 'male' },
  // ... 其他資料
];

以年齡進行分組

我們可以透過簡單的迴圈和物件來實現按照年齡的分組:

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

這會輸出一個以年齡作為 key 的物件,對應值為同年齡的人物陣列

{
  '1977': [ { name: 'Will', age: 1977, sex: 'male' } ],
  '1984': [ { name: 'Grace', age: 1984, sex: 'female' } ],
  '1988': [ { name: 'Wes', age: 1988, sex: 'female' } ],
  '1993': [ { name: 'Eric', age: 1993, sex: 'male' } ],
  '1995': [ { name: 'Charlie', age: 1995, sex: 'female' } ],
  '1998': [ { name: 'Wes', age: 1998, sex: 'male' } ]
}

以性別進行分組

如果我們想按照性別來分組,只需要將 key 改為 item.sex

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

這樣會輸出一個以性別作為 key 的物件

{
  female: [
    { name: 'Wes', age: 1988, sex: 'female' },
    { name: 'Charlie', age: 1995, sex: 'female' },
    { name: 'Grace', age: 1984, sex: 'female' }
  ],
  male: [
    { name: 'Will', age: 1977, sex: 'male' },
    { name: 'Eric', age: 1993, sex: 'male' },
    { name: 'Wes', age: 1998, sex: 'male' }
  ]
}

建立通用的 groupBy 函數

為了避免重複的 code ,所以我們把這個邏輯抽出來,變成一個通用的 groupBy 函數

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

你可以用這個函數進行各種分組,例如按年齡或性別
運行的結果會跟前面的案例一樣

自定義分組函數

我們可以讓 groupBy 更加靈活,允許傳入一個函數作為分組規則

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

這樣,你可以根據需求自行定義分組的 key,例如 item => ${item.age} - ${item.sex}

// 輸出
{
  '1988-female': [ { name: 'Wes', age: 1988, sex: 'female' } ],
  '1977-male': [ { name: 'Will', age: 1977, sex: 'male' } ],
  '1993-male': [ { name: 'Eric', age: 1993, sex: 'male' } ],
  '1995-female': [ { name: 'Charlie', age: 1995, sex: 'female' } ],
  '1984-female': [ { name: 'Grace', age: 1984, sex: 'female' } ],
  '1998-male': [ { name: 'Wes', age: 1998, sex: 'male', address: [Object] } ]
}

字串或函數,隨你選

最後,為了讓 groupBy 更加易用,我們讓它既可以接受一個屬性名字串,也可以接受一個函數

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

今天就算是數字陣列也沒有問題

// 數字陣列
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9];
console.log(groupBy(numbers, (item) => item % 2 === 0 ? 'even' : 'odd'));
// 得到
{ odd: [ 1, 3, 5, 7, 9 ], even: [ 2, 4, 6, 8 ] }

結論

通過今天的分享,我們學習了如何實現一個靈活而且可通用的陣列分組函數,這個函數不僅可以接受一個回調函數來自定義分組的規則,還能接受一個屬性名字串來快速分組,所以無論是簡單還是複雜的分組需求,都可以輕鬆應對,那麼這次的分享到這邊~謝謝大家~~~明天見!


上一篇
Day8 - 移動端頁面寬高自適應
下一篇
Day10 - ES6 Set 實作聯集、交集和差集
系列文
JavaScript 是什麼?可以吃嗎?20
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言