PHP 数组排序详解

数组排序是 PHP 中常见的数据处理操作,PHP 提供了丰富的排序函数来满足不同的排序需求,包括升序、降序、按键排序、按值排序等。

PHP 数组排序函数概述

PHP 提供了多种数组排序函数,可以根据不同的需求选择合适的排序方法:

sort()

对索引数组进行升序排列

按值排序,重置键名

rsort()

对索引数组进行降序排列

按值排序,重置键名

asort()

根据关联数组的值进行升序排列

保持键值关联

arsort()

根据关联数组的值进行降序排列

保持键值关联

ksort()

根据关联数组的键进行升序排列

按键名排序

krsort()

根据关联数组的键进行降序排列

按键名排序

排序函数对比表

函数名 排序依据 排序顺序 保持键名 适用数组类型
sort() 值 升序 否 索引数组
rsort() 值 降序 否 索引数组
asort() 值 升序 是 关联数组
arsort() 值 降序 是 关联数组
ksort() 键 升序 是 关联数组
krsort() 键 降序 是 关联数组

sort() - 对数组进行升序排列

sort() 函数对数组按值进行升序排序,并重新分配数字索引。

字符串数组排序

<?php
$cars = array("Volvo", "BMW", "Toyota");
echo "排序前: ";
print_r($cars);

sort($cars);
echo "排序后: ";
print_r($cars);
?>
输出:
排序前: Array
(
    [0] => Volvo
    [1] => BMW
    [2] => Toyota
)
排序后: Array
(
    [0] => BMW
    [1] => Toyota
    [2] => Volvo
)

数字数组排序

<?php
$numbers = array(4, 6, 2, 22, 11);
echo "排序前: ";
print_r($numbers);

sort($numbers);
echo "排序后: ";
print_r($numbers);

// 注意:键名被重新索引
echo "第一个元素: " . $numbers[0];
?>

注意: sort() 函数会重新分配数字索引,原来的键名将丢失。如果需要保持键值关联,请使用 asort()。

rsort() - 对数组进行降序排列

rsort() 函数对数组按值进行降序排序,并重新分配数字索引。

字符串数组降序排序

<?php
$fruits = array("apple", "banana", "cherry", "date");
echo "排序前: ";
print_r($fruits);

rsort($fruits);
echo "排序后: ";
print_r($fruits);
?>

数字数组降序排序

<?php
$scores = array(85, 92, 78, 96, 88);
echo "分数排序前: ";
print_r($scores);

rsort($scores);
echo "分数排序后(降序): ";
print_r($scores);

// 实际应用:显示排名
echo "分数排名: <br>";
foreach ($scores as $rank => $score) {
    echo ($rank + 1) . ". " . $score . "分<br>";
}
?>

asort() - 根据数组的值进行升序排列

asort() 函数对关联数组按值进行升序排序,并保持键值关联。

关联数组按值升序排序

<?php
$age = array("Peter" => 35, "Ben" => 37, "Joe" => 43, "Alice" => 28);
echo "排序前: ";
print_r($age);

asort($age);
echo "按年龄升序排序: ";
print_r($age);

// 遍历排序后的数组
foreach ($age as $name => $ageValue) {
    echo "$name 的年龄是 $ageValue<br>";
}
?>

产品价格排序

<?php
$products = array(
    "笔记本电脑" => 4500,
    "智能手机" => 3200,
    "平板电脑" => 2800,
    "智能手表" => 1200
);

echo "产品价格排序前: <br>";
foreach ($products as $product => $price) {
    echo "$product: ¥$price<br>";
}

asort($products);
echo "<br>按价格升序排序: <br>";
foreach ($products as $product => $price) {
    echo "$product: ¥$price<br>";
}
?>

arsort() - 根据数组的值进行降序排列

arsort() 函数对关联数组按值进行降序排序,并保持键值关联。

关联数组按值降序排序

<?php
$age = array("Peter" => 35, "Ben" => 37, "Joe" => 43, "Alice" => 28);
echo "排序前: ";
print_r($age);

arsort($age);
echo "按年龄降序排序: ";
print_r($age);
?>

学生成绩排名

<?php
$studentScores = array(
    "张三" => 85,
    "李四" => 92,
    "王五" => 78,
    "赵六" => 96,
    "钱七" => 88
);

arsort($studentScores);
echo "学生成绩排名(从高到低): <br>";
$rank = 1;
foreach ($studentScores as $student => $score) {
    echo "$rank. $student: $score 分<br>";
    $rank++;
}
?>

ksort() - 根据数组的键进行升序排列

ksort() 函数对关联数组按键进行升序排序。

按键名升序排序

<?php
$countryCodes = array(
    "CN" => "中国",
    "US" => "美国",
    "JP" => "日本",
    "UK" => "英国",
    "DE" => "德国"
);

echo "排序前: ";
print_r($countryCodes);

ksort($countryCodes);
echo "按国家代码升序排序: ";
print_r($countryCodes);
?>

月份数据排序

<?php
$monthlyData = array(
    "March" => 1500,
    "January" => 1200,
    "December" => 1800,
    "June" => 1400,
    "September" => 1600
);

echo "月度数据(按键排序前): <br>";
foreach ($monthlyData as $month => $value) {
    echo "$month: $value<br>";
}

ksort($monthlyData);
echo "<br>按月份名称升序排序: <br>";
foreach ($monthlyData as $month => $value) {
    echo "$month: $value<br>";
}
?>

krsort() - 根据数组的键进行降序排列

krsort() 函数对关联数组按键进行降序排序。

按键名降序排序

<?php
$productCategories = array(
    "A100" => "电子产品",
    "B200" => "服装",
    "C300" => "食品",
    "D400" => "家居"
);

echo "排序前: ";
print_r($productCategories);

krsort($productCategories);
echo "按分类代码降序排序: ";
print_r($productCategories);
?>

版本号排序

<?php
$versions = array(
    "v1.0" => "初始版本",
    "v2.1" => "功能更新",
    "v1.5" => "小版本更新",
    "v3.0" => "重大更新"
);

krsort($versions);
echo "版本号降序排序(最新版本在前): <br>";
foreach ($versions as $version => $description) {
    echo "$version: $description<br>";
}
?>

自然排序算法

PHP 还提供了自然排序算法,可以更人性化地处理包含数字的字符串排序。

natsort() - 自然顺序排序

自然排序 vs 常规排序

<?php
$files = array("img12.png", "img10.png", "img2.png", "img1.png");

echo "原始数组: ";
print_r($files);

// 常规排序
$standardSort = $files;
sort($standardSort);
echo "常规排序: ";
print_r($standardSort);

// 自然排序
$naturalSort = $files;
natsort($naturalSort);
echo "自然排序: ";
print_r($naturalSort);
?>

natcasesort() - 不区分大小写的自然排序

不区分大小写的自然排序

<?php
$mixedCase = array("IMG1.png", "img12.png", "IMG10.png", "img2.png");

echo "原始数组: ";
print_r($mixedCase);

natcasesort($mixedCase);
echo "不区分大小写的自然排序: ";
print_r($mixedCase);
?>

用户自定义排序

PHP 允许使用自定义比较函数进行排序,提供了更大的灵活性。

usort() - 使用用户自定义函数对数组排序

自定义排序规则

<?php
$products = array(
    array("name" => "笔记本电脑", "price" => 4500, "weight" => 2.5),
    array("name" => "智能手机", "price" => 3200, "weight" => 0.2),
    array("name" => "平板电脑", "price" => 2800, "weight" => 0.6),
    array("name" => "智能手表", "price" => 1200, "weight" => 0.1)
);

// 按价格排序
usort($products, function($a, $b) {
    return $a['price'] - $b['price'];
});

echo "按价格升序排序: <br>";
foreach ($products as $product) {
    echo $product['name'] . ": ¥" . $product['price'] . "<br>";
}

echo "<br>";

// 按重量排序
usort($products, function($a, $b) {
    return $a['weight'] * 100 - $b['weight'] * 100; // 避免浮点数比较问题
});

echo "按重量升序排序: <br>";
foreach ($products as $product) {
    echo $product['name'] . ": " . $product['weight'] . "kg<br>";
}
?>

uksort() - 使用自定义函数按键排序

自定义键排序规则

<?php
$data = array(
    "item_10" => "值10",
    "item_2" => "值2",
    "item_1" => "值1",
    "item_20" => "值20"
);

// 按数字部分排序
uksort($data, function($a, $b) {
    $numA = intval(str_replace('item_', '', $a));
    $numB = intval(str_replace('item_', '', $b));
    return $numA - $numB;
});

echo "按键中数字部分排序: <br>";
foreach ($data as $key => $value) {
    echo "$key: $value<br>";
}
?>

多维数组排序

对于多维数组,可以使用自定义排序函数来实现复杂的排序需求。

学生数据多级排序

<?php
$students = array(
    array("name" => "张三", "age" => 20, "score" => 85),
    array("name" => "李四", "age" => 22, "score" => 92),
    array("name" => "王五", "age" => 20, "score" => 78),
    array("name" => "赵六", "age" => 21, "score" => 85),
    array("name" => "钱七", "age" => 22, "score" => 88)
);

// 按年龄升序,同年龄按分数降序排序
usort($students, function($a, $b) {
    // 先按年龄比较
    if ($a['age'] != $b['age']) {
        return $a['age'] - $b['age'];
    }
    // 年龄相同,按分数降序
    return $b['score'] - $a['score'];
});

echo "学生数据排序(年龄升序,同年龄分数降序): <br>";
foreach ($students as $student) {
    echo "姓名: " . $student['name'] . ", 年龄: " . $student['age'] . ", 分数: " . $student['score'] . "<br>";
}
?>

产品数据复杂排序

<?php
$products = array(
    array("category" => "电子产品", "name" => "iPhone", "price" => 6999, "rating" => 4.5),
    array("category" => "电子产品", "name" => "iPad", "price" => 3299, "rating" => 4.3),
    array("category" => "服装", "name" => "T恤", "price" => 99, "rating" => 4.2),
    array("category" => "服装", "name" => "牛仔裤", "price" => 299, "rating" => 4.4),
    array("category" => "家居", "name" => "台灯", "price" => 159, "rating" => 4.1)
);

// 按分类字母顺序,同分类按评分降序排序
usort($products, function($a, $b) {
    // 先按分类比较
    $categoryCompare = strcmp($a['category'], $b['category']);
    if ($categoryCompare != 0) {
        return $categoryCompare;
    }
    // 同分类按评分降序
    return $b['rating'] * 10 - $a['rating'] * 10; // 避免浮点数比较问题
});

echo "产品数据排序: <br>";
foreach ($products as $product) {
    echo "分类: " . $product['category'] . ", 名称: " . $product['name'] .
         ", 价格: ¥" . $product['price'] . ", 评分: " . $product['rating'] . "<br>";
}
?>

实际应用场景

电子商务产品排序

多条件产品排序

<?php
// 模拟电子商务产品数据
$products = array(
    array("id" => 1, "name" => "iPhone 14", "price" => 5999, "sales" => 1500, "rating" => 4.7),
    array("id" => 2, "name" => "Samsung Galaxy", "price" => 4999, "sales" => 1200, "rating" => 4.5),
    array("id" => 3, "name" => "小米手机", "price" => 2999, "sales" => 2000, "rating" => 4.6),
    array("id" => 4, "name" => "华为Mate", "price" => 4599, "sales" => 1800, "rating" => 4.8)
);

// 价格排序函数
function sortByPrice($products, $order = 'asc') {
    usort($products, function($a, $b) use ($order) {
        if ($order === 'asc') {
            return $a['price'] - $b['price'];
        } else {
            return $b['price'] - $a['price'];
        }
    });
    return $products;
}

// 销量排序函数
function sortBySales($products, $order = 'desc') {
    usort($products, function($a, $b) use ($order) {
        if ($order === 'asc') {
            return $a['sales'] - $b['sales'];
        } else {
            return $b['sales'] - $a['sales'];
        }
    });
    return $products;
}

// 评分排序函数
function sortByRating($products, $order = 'desc') {
    usort($products, function($a, $b) use ($order) {
        if ($order === 'asc') {
            return $a['rating'] * 10 - $b['rating'] * 10;
        } else {
            return $b['rating'] * 10 - $a['rating'] * 10;
        }
    });
    return $products;
}

// 测试不同的排序方式
echo "=== 按价格升序排序 ===<br>";
$priceSorted = sortByPrice($products, 'asc');
foreach ($priceSorted as $product) {
    echo $product['name'] . " - ¥" . $product['price'] . "<br>";
}

echo "<br>=== 按销量降序排序 ===<br>";
$salesSorted = sortBySales($products, 'desc');
foreach ($salesSorted as $product) {
    echo $product['name'] . " - 销量: " . $product['sales'] . "<br>";
}

echo "<br>=== 按评分降序排序 ===<br>";
$ratingSorted = sortByRating($products, 'desc');
foreach ($ratingSorted as $product) {
    echo $product['name'] . " - 评分: " . $product['rating'] . "<br>";
}
?>

数据分析报表

销售数据排序分析

<?php
// 月度销售数据
$monthlySales = array(
    "一月" => array("revenue" => 150000, "profit" => 45000, "growth" => 12.5),
    "二月" => array("revenue" => 165000, "profit" => 52000, "growth" => 10.0),
    "三月" => array("revenue" => 142000, "profit" => 41000, "growth" => 8.5),
    "四月" => array("revenue" => 178000, "profit" => 58000, "growth" => 15.2)
);

// 按收入排序
uasort($monthlySales, function($a, $b) {
    return $b['revenue'] - $a['revenue'];
});

echo "=== 按收入降序排序 ===<br>";
foreach ($monthlySales as $month => $data) {
    echo "$month: 收入 ¥" . number_format($data['revenue']) .
         ", 利润 ¥" . number_format($data['profit']) .
         ", 增长率 " . $data['growth'] . "%<br>";
}

echo "<br>";

// 按增长率排序
uasort($monthlySales, function($a, $b) {
    return $b['growth'] * 100 - $a['growth'] * 100;
});

echo "=== 按增长率降序排序 ===<br>";
foreach ($monthlySales as $month => $data) {
    echo "$month: 增长率 " . $data['growth'] . "%, 收入 ¥" .
         number_format($data['revenue']) . "<br>";
}
?>

性能优化和最佳实践

排序性能优化建议:

  • 对于大型数组,选择合适的排序算法很重要
  • sort() 系列函数通常比自定义排序函数更快
  • 避免在排序函数中进行复杂的计算或数据库查询
  • 对于需要多次排序的情况,考虑缓存排序结果
  • 使用合适的排序标志来提高特定场景下的性能

排序标志的使用

使用排序标志优化性能

<?php
$numbers = array(10, 2, 35, 4, 15);

// 常规排序
sort($numbers);
echo "常规排序: ";
print_r($numbers);

// 使用排序标志
$numbers = array(10, 2, 35, 4, 15);
sort($numbers, SORT_NUMERIC);
echo "数值排序: ";
print_r($numbers);

$strings = array("10", "2", "35", "4", "15");
sort($strings, SORT_STRING);
echo "字符串排序: ";
print_r($strings);

// 自然排序标志
$files = array("img12.png", "img10.png", "img2.png", "img1.png");
sort($files, SORT_NATURAL);
echo "自然排序: ";
print_r($files);
?>

避免常见的排序错误

常见错误和解决方案

<?php
// 错误1:在自定义排序函数中返回布尔值
$numbers = array(3, 1, 4, 1, 5);
/*
usort($numbers, function($a, $b) {
    return $a > $b; // 错误:应该返回 -1, 0, 1
});
*/

// 正确做法:返回整数
usort($numbers, function($a, $b) {
    if ($a == $b) return 0;
    return ($a < $b) ? -1 : 1;
});

// 错误2:忽略浮点数比较的精度问题
$prices = array(10.1, 10.01, 10.001);
usort($prices, function($a, $b) {
    // return $a - $b; // 可能产生精度问题
    return ($a * 1000) - ($b * 1000); // 更好的方式
});

// 错误3:在排序过程中修改原数组
$data = array(3, 1, 4);
sort($data);
// 现在 $data 已经被修改,原始顺序丢失
?>

PHP 7/8 排序新特性

太空船运算符(PHP 7+)

使用太空船运算符简化排序

<?php
$numbers = array(3, 1, 4, 1, 5);

// PHP 7+ 使用太空船运算符
usort($numbers, function($a, $b) {
    return $a <=> $b; // 升序排序
});

echo "升序排序: ";
print_r($numbers);

// 降序排序
usort($numbers, function($a, $b) {
    return $b <=> $a; // 降序排序
});

echo "降序排序: ";
print_r($numbers);

// 多维数组排序示例
$students = array(
    array("name" => "张三", "score" => 85),
    array("name" => "李四", "score" => 92),
    array("name" => "王五", "score" => 78)
);

usort($students, function($a, $b) {
    return $b['score'] <=> $a['score']; // 按分数降序
});

echo "学生按分数降序排序: <br>";
foreach ($students as $student) {
    echo $student['name'] . ": " . $student['score'] . "分<br>";
}
?>

总结

  • sort() / rsort() - 对索引数组按值排序,重置键名
  • asort() / arsort() - 对关联数组按值排序,保持键值关联
  • ksort() / krsort() - 对关联数组按键排序
  • natsort() / natcasesort() - 自然顺序排序
  • usort() / uasort() / uksort() - 使用自定义函数排序
  • PHP 7+ 的太空船运算符 <=> 可以简化比较逻辑
  • 选择合适的排序函数和标志可以提高性能
  • 对于复杂排序需求,可以使用多维数组和自定义排序函数

完整的 PHP 数组参考手册

如需查看所有数组函数的完整参考手册,请访问我们的 PHP Array 参考手册。

该参考手册提供了每个函数的详细描述、参数说明和应用实例!