首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP 二維數組多字段排序方案對比

     編輯:PHP 相關知識

二維數組排序是業務開發高頻需求。本文對比 array_multisort 與 usort 兩大主流方案,分析適用場景、性能差異、代碼複雜度,提供選型指南。

場景示例

$users = [
    ['name' => 'Tom',   'age' => 20, 'score' => 85],
    ['name' => 'Ann',   'age' => 18, 'score' => 92],
    ['name' => 'Jack',  'age' => 22, 'score' => 85],
    ['name' => 'Lucy',  'age' => 18, 'score' => 78],
];

需求:年齡升序,年齡相同則分數降序。

方案一:array_multisort (提取列排序)

// 1. 提取排序列
$ages = array_column($users, 'age');
$scores = array_column($users, 'score');

// 2. 多鍵排序 (引用傳遞,修改原數組)
array_multisort($ages, SORT_ASC, $scores, SORT_DESC, $users);

/* 結果:
[
    ['name'=>'Ann',  'age'=>18, 'score'=>92], // 年齡最小,分數最高
    ['name'=>'Lucy', 'age'=>18, 'score'=>78], // 年齡相同,分數較低
    ['name'=>'Tom',  'age'=>20, 'score'=>85],
    ['name'=>'Jack', 'age'=>22, 'score'=>85],
]
*/

優點

  • 內置函數,無需寫比較邏輯
  • 多鍵排序語義清晰
  • 支持 SORT_NUMERIC/SORT_STRING/SORT_NATURAL 等標誌

缺點

  • 需預先提取所有排序列到獨立數組
  • 大數組時內存開銷大 (複製數據)
  • 複雜邏輯 (如字符串長度、自定義計算) 不靈活

方案二:usort (自定義比較函數)

usort($users, function($a, $b) {
    // 年齡升序
    if ($a['age'] != $b['age']) {
        return $a['age'] <=> $b['age'];
    }
    // 年齡相同,分數降序
    return $b['score'] <=> $a['score'];
});

/* 同樣結果,邏輯完全可控 */

優點

  • 極致靈活:任意計算、嵌套結構、外部數據關聯
  • 無額外內存開銷 (原地排序)
  • 代碼集中,易維護

缺點

  • 需編寫比較邏輯
  • 回調函數調用開銷大,大數組 (10萬+) 明顯慢於 array_multisort
  • PHP 7.0 前需注意返回值規範 (<0, 0, >0)

性能基準測試 (參考)

<?php
$data = [];
for ($i = 0; $i < 50000; $i++) {
    $data[] = ['age' => rand(18, 60), 'score' => rand(0, 100)];
}

$copy1 = $data;
$copy2 = $data;

// array_multisort
$start = microtime(true);
$ages = array_column($copy1, 'age');
$scores = array_column($copy1, 'score');
array_multisort($ages, SORT_ASC, $scores, SORT_DESC, $copy1);
echo "array_multisort: " . (microtime(true) - $start) . "s\n";

// usort
$start = microtime(true);
usort($copy2, function($a, $b) {
    if ($a['age'] != $b['age']) return $a['age'] <=> $b['age'];
    return $b['score'] <=> $a['score'];
});
echo "usort: " . (microtime(true) - $start) . "s\n";

/* 典型輸出:
array_multisort: 0.045s
usort: 0.082s (約 2x 慢)
*/

進階:通用多字段排序封裝

/**
 * 通用多字段排序 (基於 usort,靈活優先)
 * @param array &$data 數據引用
 * @param array $fields ['field' => SORT_ASC|SORT_DESC, ...]
 * @param callable|null $preprocess 值預處理 fn($item, $field)
 */
function multiSort(array &$data, array $fields, callable $preprocess = null) {
    usort($data, function($a, $b) use ($fields, $preprocess) {
        foreach ($fields as $field => $direction) {
            $valA = $preprocess ? $preprocess($a, $field) : ($a[$field] ?? null);
            $valB = $preprocess ? $preprocess($b, $field) : ($b[$field] ?? null);
            
            if ($valA == $valB) continue;
            
            $cmp = $valA <=> $valB;
            return $direction === SORT_DESC ? -$cmp : $cmp;
        }
        return 0;
    });
}

// 使用示例
multiSort($users, [
    'age' => SORT_ASC,
    'score' => SORT_DESC,
]);

// 複雜場景:按名稱長度降序
multiSort($users, [
    'name' => SORT_DESC,
], fn($item, $field) => strlen($item[$field]));

選型決策樹

  1. 數據量 < 1萬、排序邏輯固定標準 → array_multisort 簡潔優雅
  2. 數據量大、或邏輯複雜 (計算衍生值、多層嵌套、外部關聯) → usort 靈活可控
  3. 需要穩定排序 (相等元素保持原序) → PHP 7+ 兩者均穩定
  4. 多維數組/矩陣同步排序 → array_multisort 專為此設計

現代最佳實踐

  • 默認使用 usort + 箭頭函數,代碼可讀性最高
  • 性能敏感熱路徑才考慮 array_multisort
  • 避免在比較函數中做重計算,預處理衍生字段
  • 考慮 SplHeap/SplPriorityQueue 實現增量排序/Top-K

理解兩者機制差異,根據業務場景靈活選擇,才能寫出高性能、可維護的排序代碼。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved