在PHP中,usort()函数如何工作?

29

我查看了PHP文档和在线教程,但它们都没有解释usort的实际工作原理。以下是我正在尝试的示例:

$data = array(

    array('msg' => 'some text','month' => 11,'level' => 10),

    array('msg' => 'some text','month' => 5,'level' => 10),

    array('msg' => 'some text','month' => 8,'level' => 10),

    array('msg' => 'some text','month' => 12,'level' => 10),

    array('msg' => 'some text','month' => 2,'level' => 10),

    array('msg' => 'some text','month' => 3,'level' => 10),

    array('msg' => 'some text','month' => 4,'level' => 10),

    array('msg' => 'some text','month' => 7,'level' => 10),

    array('msg' => 'some text','month' => 10,'level' => 10),

    array('msg' => 'some text','month' => 1,'level' => 10),

    array('msg' => 'some text','month' => 6,'level' => 10),

    array('msg' => 'some text','month' => 9,'level' => 10)

);

我想要能够按照12到1的顺序(因为它们是无组织的)对月份进行排序,通过一些帮助,这是解决方案。

function cmp($a, $b)
{
    if ($a["month"] == $b["month"]) 
    {
       return 0;
    }
    return ($a["month"] < $b["month"]) ? -1 : 1;
}

usort($data, "cmp");

但我不明白函数cmp是如何对数组进行排序的。我尝试了如下代码打印出每个变量$a和$b:

function cmp($a, $b)
{
   echo "a: ".$a['month']."<br/>";
   echo " b: ".$b['month']."<br/>";
   echo "<br/><br/>";
}

输出结果为

a: 3
b: 5

a: 9
b: 3

a: 3
b: 8

a: 6
b: 3

a: 3
b: 12

a: 1
b: 3

a: 3
b: 2

a: 10
b: 3

a: 3
b: 11

a: 7
b: 3

a: 4
b: 3

a: 12
b: 2

a: 5
b: 12

a: 12
b: 11

a: 8
b: 12

a: 5
b: 8

a: 2
b: 11

a: 6
b: 9

a: 7
b: 6

a: 6
b: 4

a: 10
b: 6

a: 1
b: 6

a: 9
b: 4

a: 7
b: 1

a: 10
b: 7

对于这个排序是如何工作以及为什么要使用cmp($a,$b)没有多少意义。我尝试打印出所有的过程,如你所见,但并未找到任何解决方案来理解它是如何工作的。

谢谢


@col 你需要将数组包含到你正在进行的测试中。 - Exploit
当然这是公共信息。毕竟你可以下载PHP源代码:)。我现在感到有些懒得自己查看,但我会相信PaulPRO它使用了一个快速排序实现。如果想要更多细节,请阅读PHP源代码。 - Corbin
什么?什么测试?你的第二个 cmp 函数没有返回任何值,意味着总是返回 0。使用它运行 usort 没有任何意义。 - Your Common Sense
@Col.Shrapnel,您能否将您正在尝试的所有代码粘贴在一起,这样我就可以告诉您缺少了什么? - Exploit
我在谈论的是你的代码。已经粘贴在你的问题中了。你能看到你的代码中第二个变量的cmp函数吗? - Your Common Sense
显示剩余3条评论
5个回答

33

函数cmp本身不执行排序,它只是告诉usort一个值是否比另一个值小、相等还是大。例如,如果$a=5$b=9,则它将返回1,以指示$b中的值大于$a中的值。

排序由usort执行。


哇,你说的很有道理。我应该早点看到这个问题。我是否总是需要输入两个参数到cmp函数中? - Exploit
1
是的,比较函数总是需要两个参数。 - halfdan
1
我认为它会返回-1(而不是Halfdan提到的1),以表示$b中的值大于$a中的值。 - Sid

30

在 PHP 的排序函数中提供的回调函数有三个返回值:

0:  both elements are the same
-1 (<0): the first element is smaller than the second
1 (>0):  the first element is greater

现在,usort可能在内部使用快速排序或合并排序。对于每次比较,它会调用你的回调函数来比较两个元素,然后决定是否需要交换它们。


3
+1 这正是我所需要的。在 PHP 文档中,他们说 PHP 版本低于 7 的限制为“-2147483648 到 2147483647”,但他们没有像你这样清楚地表述。你的解释会使文档变得更加清晰明了! - mrClean

14

usort() 使用一个实现了快速排序的算法来对数组进行排序,它会调用你的 cmp 函数多次,直到完全使用该算法对数组排序。


Usort使用计数排序而不是快速排序。请查看http://www.ijest.info/docs/IJEST11-03-09-057.pdf。 - user1613360
@user1613360,您误将PHP的usort与那篇论文中提到的usort算法混淆了。PHP的usort是使用快速排序实现的。 - Paul
你可以在这里了解更多关于PHP排序的信息(http://php.net/sort),但是是的,正如提到的,默认情况下PHP中大多数排序使用快速排序。请参见链接中的注释。 - aug

4

正如其他人所提到的,usort使用了快速排序算法。此外,你不需要显式比较两个字符串。你可以使用PHP的字符串比较方法。

你创建的函数,

function cmp($a, $b)
{
    if ($a["month"] == $b["month"]) 
    {
       return 0;
    }
    return ($a["month"] < $b["month"]) ? -1 : 1;
}

可以简单地写成以下内容:
function compareMyStrings($a, $b){
    return strnatcmp($a["month"], $b["month"]);
}

希望以下内容能帮到您!

0

这是我找到的另一种解决方案

<?php 
$users = array( array( "peter", "male", "46"), 
                array( "hans", "male", "19"), 
                array( "john", "male", "30"), 
                array( "linda", "female", "54"), 
                array( "erika", "female", "79")); 
usort($users, "whatevername"); 
function whatevername($whatever1, $whatever2) 
{ 
    // $whatever1 and $whatever2 are items from the $user array. 
    // index [2] is the age. 
    // Check if $whatever1 is older than $whatever2. 
    // Return 1 tells usort to swap the positions. 
    return $whatever1[2] > $whatever2[2]; 
} 

echo("<pre>"); 
print_r($users); 
echo("</pre>"); 
?>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接