0

0

PHP usort 自定义排序:将未匹配项高效置于数组末尾的策略

碧海醫心

碧海醫心

发布时间:2025-11-26 13:34:02

|

587人浏览过

|

来源于php中文网

原创

PHP usort 自定义排序:将未匹配项高效置于数组末尾的策略

本文详细探讨了如何使用 php 的 `usort` 函数,在依据一个预设的参考数组对多维数组进行自定义排序时,正确处理那些未包含在参考数组中的元素。通过分析原始代码的不足,文章提出了一种健壮的解决方案,即为未匹配项分配一个极大的排序权重(如 `php_int_max`),从而确保它们被统一放置在排序结果的末尾,并提供了详细的代码示例和注意事项。

理解 usort 与自定义排序

在 PHP 中,usort() 函数允许开发者使用自定义的比较函数对数组进行排序。这个比较函数(或称为回调函数)接收两个参数(通常是数组中的两个元素),并根据它们之间所需的相对顺序返回一个整数:

  • 如果第一个参数应排在第二个参数之前,返回负数(例如 -1)。
  • 如果第一个参数应排在第二个参数之后,返回正数(例如 1)。
  • 如果两个参数的顺序无关紧要(或被认为是相等),返回 0。

当我们需要根据一个预定义的顺序(例如一个字符串数组)来对另一个复杂数组进行排序时,usort() 是一个非常强大的工具。然而,一个常见的挑战是,当被排序的数组中包含一些元素,而这些元素并未出现在我们预定义的参考顺序中时,如何正确处理它们。通常,我们希望这些未匹配的元素被统一放置在排序结果的末尾。

原始问题分析

假设我们有一个多维数组 $itemsToSort,需要根据另一个参考数组 $sortOrder 对其进行排序。$itemsToSort 中的每个子项的第一个元素($item[0])将用于与 $sortOrder 进行匹配。目标是让 $sortOrder 中定义的元素按其在 $sortOrder 中的顺序排列,而未在 $sortOrder 中定义的元素则被放置到数组的末尾。

一个常见的错误实现方式可能如下:

立即学习PHP免费学习笔记(深入)”;

usort($itemsToSort, function($a, $b) use ($sortOrder){
   $valA = array_search($a[0], $sortOrder);
   $valB = array_search($b[0], $sortOrder);

   if ($valA === false) // 如果 A 未找到
      return -1; // 尝试将 A 放在 B 之前
   if ($valB === false) // 如果 B 未找到(此时 A 必然已找到)
      return 0; // 认为 A 和 B 顺序不变

   // 如果 A 和 B 都找到,则按其在 $sortOrder 中的索引比较
   if ($valA > $valB)
      return 1;
   if ($valA < $valB)
      return -1;
   return 0;
});

上述代码存在逻辑缺陷:

Elser AI Comics
Elser AI Comics

一个免费且强大的AI漫画生成工具,助力你三步创作自己的一出好戏

下载
  1. if ($valA === false) return -1;:如果 $a[0] 未在 $sortOrder 中找到,此语句会返回 -1,这意味着 $a 会被排在 $b 之前。这与“将未匹配项置于末尾”的目标相悖,因为一个未匹配项不应该排在一个已匹配项之前。
  2. if ($valB === false) return 0;:此语句仅在 $valA !== false(即 $a 已找到)的情况下执行。如果此时 $valB === false(即 $b 未找到),返回 0 意味着 $a 和 $b 的相对顺序不变。然而,正确的逻辑应该是将已找到的 $a 排在未找到的 $b 之前,即返回 -1。

这些逻辑错误导致当参考数组中只指定了少量值时,排序结果无法达到预期。

解决方案:为未匹配项分配最大权重

要解决这个问题,我们可以为那些未在 $sortOrder 中找到的元素分配一个“虚拟”的、极大的排序权重。这样,在比较时,这些具有极大权重的元素自然会排在所有具有正常(较小)权重的元素之后。PHP 提供了一个常量 PHP_INT_MAX,它代表了 PHP 能处理的最大整数值,非常适合作为这种“极大权重”的代表。

示例代码

以下是使用 PHP_INT_MAX 策略的改进 usort 回调函数:

 $rankB) {
        return 1; // A 排在 B 之后
    }
    if ($rankA < $rankB) {
        return -1; // A 排在 B 之前
    }
    return 0; // 权重相等,保持原有相对顺序(或认为相等)
});

echo "\n排序后的数组:\n";
print_r($itemsToSort);

?>

代码解析

  1. array_search($a[0], $sortOrder): 此函数用于查找 $a[0] 在 $sortOrder 数组中的键名(即索引)。如果找到,它会返回相应的整数索引;如果未找到,则返回布尔值 false。
  2. ($rankA === false) ? PHP_INT_MAX : $rankA;: 这是一个三元运算符。它的作用是:
    • 如果 $rankA(或 $rankB)为 false,表示对应的元素未在 $sortOrder 中找到,那么将其排序权重设置为 PHP_INT_MAX。
    • 如果 $rankA 不为 false,表示元素已找到,则保留其在 $sortOrder 中的实际索引作为排序权重。
  3. 最终比较: 经过上述处理后,所有的元素都有了一个数值型的排序权重。我们只需直接比较 $rankA 和 $rankB 即可。
    • if ($rankA > $rankB) return 1;:如果 A 的权重更大(索引值更大或为 PHP_INT_MAX),则 A 排在 B 之后。
    • if ($rankA
    • return 0;:如果权重相等,则保持它们的相对顺序。这适用于两种情况:一是两个元素都在 $sortOrder 中且具有相同的索引(通常不会发生,除非 $sortOrder 有重复值且 array_search 找到的是第一个);二是两个元素都未在 $sortOrder 中找到,都分配了 PHP_INT_MAX。

运行结果

原始数组:
Array
(
    [0] => Array
        (
            [0] => itemC
            [1] => dataC
        )

    [1] => Array
        (
            [0] => itemA
            [1] => dataA
        )

    [2] => Array
        (
            [0] => itemX
            [1] => dataX
        )

    [3] => Array
        (
            [0] => itemB
            [1] => dataB
        )

    [4] => Array
        (
            [0] => itemY
            [1] => dataY
        )

    [5] => Array
        (
            [0] => itemD
            [1] => dataD
        )

    [6] => Array
        (
            [0] => itemA
            [1] => dataA_duplicate
        )

)

排序后的数组:
Array
(
    [0] => Array
        (
            [0] => itemA
            [1] => dataA
        )

    [1] => Array
        (
            [0] => itemA
            [1] => dataA_duplicate
        )

    [2] => Array
        (
            [0] => itemB
            [1] => dataB
        )

    [3] => Array
        (
            [0] => itemC
            [1] => dataC
        )

    [4] => Array
        (
            [0] => itemX
            [1] => dataX
        )

    [5] => Array
        (
            [0] => itemY
            [1] => dataY
        )

    [6] => Array
        (
            [0] => itemD
            [1] => dataD
        )

)

从结果可以看出,itemA、itemB、itemC 按照 $sortOrder 的顺序排列,

相关专题

更多
php文件怎么打开
php文件怎么打开

打开php文件步骤:1、选择文本编辑器;2、在选择的文本编辑器中,创建一个新的文件,并将其保存为.php文件;3、在创建的PHP文件中,编写PHP代码;4、要在本地计算机上运行PHP文件,需要设置一个服务器环境;5、安装服务器环境后,需要将PHP文件放入服务器目录中;6、一旦将PHP文件放入服务器目录中,就可以通过浏览器来运行它。

2457

2023.09.01

php怎么取出数组的前几个元素
php怎么取出数组的前几个元素

取出php数组的前几个元素的方法有使用array_slice()函数、使用array_splice()函数、使用循环遍历、使用array_slice()函数和array_values()函数等。本专题为大家提供php数组相关的文章、下载、课程内容,供大家免费下载体验。

1576

2023.10.11

php反序列化失败怎么办
php反序列化失败怎么办

php反序列化失败的解决办法检查序列化数据。检查类定义、检查错误日志、更新PHP版本和应用安全措施等。本专题为大家提供php反序列化相关的文章、下载、课程内容,供大家免费下载体验。

1475

2023.10.11

php怎么连接mssql数据库
php怎么连接mssql数据库

连接方法:1、通过mssql_系列函数;2、通过sqlsrv_系列函数;3、通过odbc方式连接;4、通过PDO方式;5、通过COM方式连接。想了解php怎么连接mssql数据库的详细内容,可以访问下面的文章。

951

2023.10.23

php连接mssql数据库的方法
php连接mssql数据库的方法

php连接mssql数据库的方法有使用PHP的MSSQL扩展、使用PDO等。想了解更多php连接mssql数据库相关内容,可以阅读本专题下面的文章。

1414

2023.10.23

html怎么上传
html怎么上传

html通过使用HTML表单、JavaScript和PHP上传。更多关于html的问题详细请看本专题下面的文章。php中文网欢迎大家前来学习。

1234

2023.11.03

PHP出现乱码怎么解决
PHP出现乱码怎么解决

PHP出现乱码可以通过修改PHP文件头部的字符编码设置、检查PHP文件的编码格式、检查数据库连接设置和检查HTML页面的字符编码设置来解决。更多关于php乱码的问题详情请看本专题下面的文章。php中文网欢迎大家前来学习。

1445

2023.11.09

php文件怎么在手机上打开
php文件怎么在手机上打开

php文件在手机上打开需要在手机上搭建一个能够运行php的服务器环境,并将php文件上传到服务器上。再在手机上的浏览器中输入服务器的IP地址或域名,加上php文件的路径,即可打开php文件并查看其内容。更多关于php相关问题,详情请看本专题下面的文章。php中文网欢迎大家前来学习。

1305

2023.11.13

php与html混编教程大全
php与html混编教程大全

本专题整合了php和html混编相关教程,阅读专题下面的文章了解更多详细内容。

1

2026.01.13

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
PHP课程
PHP课程

共137课时 | 8.5万人学习

JavaScript ES5基础线上课程教学
JavaScript ES5基础线上课程教学

共6课时 | 6.9万人学习

PHP新手语法线上课程教学
PHP新手语法线上课程教学

共13课时 | 0.8万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号