對 array 進行排序或分組
第一部分:對陣列進行排序(Sorting)
排序的意思是將陣列中的元素依據某個規則排列,通常是從小到大(或大到小)。JavaScript 內建的 sort() 方法可以輕鬆做到這件事,但要注意:如果陣列是數字,sort() 預設會當成字串排序,所以會出錯(例如 [10, 2] 會變成 ['10', '2'],排序後還是 [10, 2] 但實際上是字串)。我們需要提供一個比較函式(comparison function)來修正。
步驟 1:準備一個簡單的數字陣列
先建立一個陣列,裡面放一些數字。打開瀏覽器 Console,輸入以下完整程式碼,按 Enter 執行,看看結果。
// 步驟 1:建立一個數字陣列
let numbers = [5, 2, 9, 1, 5, 6];
// 印出原始陣列,確認內容
console.log("原始陣列:", numbers);
執行後,你會看到輸出:原始陣列: [5, 2, 9, 1, 5, 6]。這是你的起點。
步驟 2:使用 sort() 進行升序排序(從小到大)
現在,我們用 sort() 方法,加上一個比較函式。比較函式是個小函式,接收兩個參數 a 和 b,如果 a - b 小於 0,就把 a 排在前面(升序)。
輸入以下完整程式碼(接續上面的 numbers 陣列):
// 步驟 2:升序排序(從小到大)
numbers.sort(function(a, b) {
    return a - b;  // 如果 a < b,回傳負數,a 排前面
});
// 印出排序後的陣列
console.log("升序排序後:", numbers);
執行後,輸出會是:升序排序後: [1, 2, 5, 5, 6, 9]。恭喜!你的陣列現在是排序好的。如果有重複數字(如兩個 5),它們會保持原相對位置。
步驟 3:使用 sort() 進行降序排序(從大到小)
如果想從大到小排序,只要把比較函式改成 b - a 就好。
輸入以下完整程式碼(你可以重設 numbers 陣列,或直接用上面的結果繼續):
// 先重設陣列(如果需要)
let numbersDesc = [5, 2, 9, 1, 5, 6];
// 降序排序(從大到小)
numbersDesc.sort(function(a, b) {
    return b - a;  // 如果 b < a,回傳負數,b 排前面
});
// 印出排序後的陣列
console.log("降序排序後:", numbersDesc);
輸出:降序排序後: [9, 6, 5, 5, 2, 1]。簡單吧?記住,sort() 會直接修改原陣列,如果你不想改原陣列,可以先用 slice() 複製一份:let copy = numbers.slice().sort(...);。
步驟 4:排序字串陣列或物件陣列
如果陣列是字串,sort() 預設就 OK(依字典順序)。如果是物件陣列(如人名和年齡),我們可以指定排序的屬性。
範例:排序物件陣列,按年齡升序。
// 步驟 4:物件陣列排序
let people = [
    { name: "小明", age: 25 },
    { name: "小華", age: 30 },
    { name: "小美", age: 20 }
];
// 按年齡升序排序
people.sort(function(a, b) {
    return a.age - b.age;  // 比較 age 屬性
});
// 印出排序後
console.log("按年齡排序:", people);
輸出會是按年齡 20, 25, 30 的順序。這樣你就能處理更複雜的資料了。
第二部分:對陣列進行分組(Grouping)
分組的意思是根據某個條件,將陣列元素分成幾個小組(像是分類)。JavaScript 沒有內建的 groupBy 方法(直到 ECMAScript 2023 才有,但為了相容性,我們用 reduce() 方法手動實現)。reduce() 就像是把陣列「歸約」成一個物件,key 是分組條件,value 是該組的子陣列。
步驟 1:準備一個可分組的陣列
我們用數字陣列,按奇偶分組。輸入以下程式碼:
// 步驟 1:建立陣列
let numbersGroup = [1, 2, 3, 4, 5, 6, 7, 8];
// 印出原始陣列
console.log("原始陣列:", numbersGroup);
輸出:原始陣列: [1, 2, 3, 4, 5, 6, 7, 8]。
步驟 2:使用 reduce() 按奇偶分組
我們建立一個空物件 groups,用 reduce() 遍歷陣列。如果數字是奇數,放進 odd 組;偶數放進 even 組。
輸入以下完整程式碼:
// 步驟 2:按奇偶分組
let groups = numbersGroup.reduce(function(accumulator, current) {
    // accumulator 是累積的結果(物件),current 是當前元素
    
    if (current % 2 === 0) {
        // 偶數:如果 accumulator.even 不存在,先建立空陣列
        if (!accumulator.even) {
            accumulator.even = [];
        }
        accumulator.even.push(current);
    } else {
        // 奇數:同上
        if (!accumulator.odd) {
            accumulator.odd = [];
        }
        accumulator.odd.push(current);
    }
    
    return accumulator;  // 回傳更新後的物件
}, {});  // 初始值是空物件 {}
// 印出分組結果
console.log("分組結果:", groups);
console.log("奇數組:", groups.odd);
console.log("偶數組:", groups.even);
執行後,輸出:
分組結果: { odd: [1, 3, 5, 7], even: [2, 4, 6, 8] }
奇數組: [1, 3, 5, 7]
偶數組: [2, 4, 6, 8]
解釋一下:
- 
reduce() 的第一個參數是 callback 函式:accumulator 是之前累積的結果,current 是當前數字。 
- 
% 2 === 0 是檢查偶數(餘數 0)。 
- 
push() 把元素加到對應陣列。 
- 
初始值 確保從空物件開始。 
步驟 3:分組物件陣列(例如按年齡區間分組)
更實用的範例:按年齡分組成「年輕」(<30)、「中年」(30-50)、「老年」(>50)。
// 步驟 3:物件陣列分組
let peopleGroup = [
    { name: "小明", age: 25 },
    { name: "小華", age: 35 },
    { name: "小美", age: 20 },
    { name: "阿姨", age: 55 },
    { name: "叔叔", age: 45 }
];
// 分組函式
let ageGroups = peopleGroup.reduce(function(accumulator, person) {
    let groupKey;
    
    if (person.age < 30) {
        groupKey = "年輕";
    } else if (person.age >= 30 && person.age <= 50) {
        groupKey = "中年";
    } else {
        groupKey = "老年";
    }
    
    // 如果該組不存在,建立空陣列
    if (!accumulator[groupKey]) {
        accumulator[groupKey] = [];
    }
    
    // 加入人
    accumulator[groupKey].push(person);
    
    return accumulator;
}, {});
// 印出分組結果
console.log("年齡分組:", ageGroups);
輸出會是像這樣:
年齡分組: {
  年輕: [{ name: '小明', age: 25 }, { name: '小美', age: 20 }],
  中年: [{ name: '小華', age: 35 }, { name: '叔叔', age: 45 }],
  老年: [{ name: '阿姨', age: 55 }]
}
這樣你就完成了分組!如果你的瀏覽器支援最新 JavaScript(ES2023),也可以用 groupBy() 方法簡化,但為了安全,我們用 reduce() 比較通用。