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 参考手册

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