略微加速

PHP官方手册 - 互联网笔记

PHP - Manual: usort

2024-04-28

usort

(PHP 4, PHP 5, PHP 7, PHP 8)

usort 使用用户自定义的比较函数对数组中的值进行排序

说明

usort(array &$array, callable $callback): bool

根据用户提供的比较函数,对 array 原地排序。

注意:

如果两个成员完全相同,那么它们将保持原来的顺序。 在 PHP 8.0.0 之前,它们在排序数组中的相对顺序是未定义的。

注意: 此函数为 array 中的元素赋与新的键名。这将删除原有的键名,而不是仅仅将键名重新排序。

参数

array

输入的数组

callback

在第一个参数小于,等于或大于第二个参数时,该比较函数必须相应地返回一个小于,等于或大于 0 的整数。

callback(mixed $a, mixed $b): int

返回值

总是返回 true

更新日志

版本 说明
8.0.0 如果 callback 接受引用传递参数,该方法将会抛出 E_WARNING

范例

示例 #1 usort() 例子

<?php
function cmp($a$b)
{
    if (
$a == $b) {
        return 
0;
    }
    return (
$a $b) ? -1;
}

$a = array(32561);

usort($a"cmp");

foreach (
$a as $key => $value) {
    echo 
"$key$value\n";
}
?>

以上例程会输出:

0: 1
1: 2
2: 3
3: 5
4: 6

注意:

很明显在这个小例子中用 sort() 函数更合适。

示例 #2 使用多维数组的 usort() 例子

<?php
function cmp($a$b)
{
    return 
strcmp($a["fruit"], $b["fruit"]);
}

$fruits[0]["fruit"] = "lemons";
$fruits[1]["fruit"] = "apples";
$fruits[2]["fruit"] = "grapes";

usort($fruits"cmp");

foreach (
$fruits as $key => $value) {
    echo 
"\$fruits[$key]: " $value["fruit"] . "\n";
}
?>

当排序多维数组时,$a$b 包含到数组第一个索引的引用。

以上例程会输出:

$fruits[0]: apples
$fruits[1]: grapes
$fruits[2]: lemons

示例 #3 使用一个对象的成员函数的 usort() 例子

<?php
class TestObj {
    private 
string $name;

    function 
__construct($name)
    {
        
$this->name $name;
    }

    
/* This is the static comparing function: */
    
static function cmp_obj($a$b)
    {
        return 
strtolower($a->name) <=> strtolower($b->name);
    }
}

$a[] = new TestObj("c");
$a[] = new TestObj("b");
$a[] = new TestObj("d");

usort($a, [TestObj::class, "cmp_obj"]);

foreach (
$a as $item) {
    echo 
$item->name "\n";
}
?>

以上例程会输出:

b
c
d

示例 #4 usort() 示例,使用闭包对多维数组进行排序

<?php
$array
[0] = array('key_a' => 'z''key_b' => 'c');
$array[1] = array('key_a' => 'x''key_b' => 'b');
$array[2] = array('key_a' => 'y''key_b' => 'a');

function 
build_sorter($key) {
    return function (
$a$b) use ($key) {
        return 
strnatcmp($a[$key], $b[$key]);
    };
}

usort($arraybuild_sorter('key_b'));

foreach (
$array as $item) {
    echo 
$item['key_a'] . ', ' $item['key_b'] . "\n";
}
?>

以上例程会输出:

y, a
x, b
z, c

示例 #5 使用太空船运算符的 usort() 示例

太空船运算符允许跨多个轴直接比较复合值。 下面的示例将对 $people 按姓氏排序,如果姓氏匹配,则按名字排序。

<?php
$people
[0] = ['first' => 'Adam''last' => 'West'];
$people[1] = ['first' => 'Alec''last' => 'Baldwin'];
$people[2] = ['first' => 'Adam''last' => 'Baldwin'];

function 
sorter(array $a, array $b) {
    return [
$a['last'], $a['first']] <=> [$b['last'], $b['first']];
}

usort($people'sorter');

foreach (
$people as $person) {
    print 
$person['last'] . ', ' $person['first'] . PHP_EOL;
}
?>

以上例程会输出:

Baldwin, Adam
Baldwin, Alec
West, Adam

参见

  • uasort() - 使用用户自定义的比较函数,保持索引和值的对应关系,原地排序 array。
  • uksort() - 使用用户自定义的比较函数对数组中的键名进行排序
  • 数组排序函数对比
add a noteadd a note

User Contributed Notes 10 notes

up
8
Hayley Watson
9 years ago
As the documentation says, the comparison function needs to return an integer that is either "less than, equal to, or greater than zero". There is no requirement to restrict the value returned to -1, 0, 1.

<?php
usort
($array, function($a, $b) {
    if(
$a->integer_property > $b->integer_property) {
        return
1;
    }
    elseif(
$a->integer_property < $b->integer_property) {
        return -
1;
    }
    else {
        return
0;
    }
});
?>

can be simplified to

<?php
usort
($array, function($a, $b) {
    return
$a->integer_property - $b->integer_property;
});
?>

This of course applies to any comparison function that calculates an integer "score" for each of its arguments to decide which is "greater".
up
7
luke dot semerau at gmail dot com
13 years ago
If you need to use usort with a key in the calling method, I wrote this as a utility:
<?php

function usort_comparison($obj, $method, $key) {
   
$usorter = &new Usort($obj, $method, $key);
    return array(
$usorter, "sort");
}

class
Usort {
    function
__construct($obj, $method, $key) {
       
$this->obj = $obj;
       
$this->method = $method;
       
$this->key = $key;
    }
    function
sort($a, $b) {
        return
call_user_func_array(array($this->obj, $this->method), array($a, $b, $this->key));
    }
}

?>

<?php

require_once("util/usort.php");

class
Foo {
   
$items = array(FooBar(13), FooBar(2));
    public function
sorter() {
       
usort($this-items, usort_comparison("Foo", "_cmp", "item"));
    }

    public static function
_cmp($a, $b, $key) {
         return
strcasecmp($a->$key, $b->$key);
    }

}

class
FooBar {
    public
$item;
    function
__construct($val) {
       
$this->item = $val;
    }
}

?>

~ simple example... but in the way I need to use it was the key was used in a switch statement to choose the different member of the object to compare against dynamically (as in, sort by x or y or z)
up
10
mkr at binarywerks dot dk
19 years ago
If you want to sort an array according to another array acting as a priority list, you can use this function.

<?php
function listcmp($a, $b)
{
  global
$order;

  foreach(
$order as $key => $value)
    {
      if(
$a==$value)
        {
          return
0;
          break;
        }

      if(
$b==$value)
        {
          return
1;
          break;
        }
    }
}

$order[0] = "first";
$order[1] = "second";
$order[2] = "third";

$array[0] = "second";
$array[1] = "first";
$array[2] = "third";
$array[3] = "fourth";
$array[4] = "second";
$array[5] = "first";
$array[6] = "second";

usort($array, "listcmp");

print_r($array);
?>
up
6
derek at luddite dot net
21 years ago
Needed a date sort and I didn't know if one was available so I wrote one. Maybe it'll help someone:

<?php
function DateSort($a,$b,$d="-") {
    if (
$a == $b) {
        return
0;
    } else { 
//Convert into dates and compare
       
list($am,$ad,$ay)=split($d,$a);
        list(
$bm,$bd,$by)=split($d,$b);
        if (
mktime(0,0,0,$am,$ad,$ay) < mktime(0,0,0,$bm,$bd,$by)) {
            return -
1;
        } else {
            return
1;
        }
    }
}
?>

$d is the delimeter
up
4
inigo dot grimbergen at gmail dot com
5 years ago
to sort with numeric and empty values  and have the smallest on top:
<?php
    usort
($list, function($a, $b) {
        if(
$a == null && $b != null ) return 1;
        if(
$a != null && $b == null ) return -1;
        return
$a > $b ? 1 : -1;
    });
?>
returns
1
2
3
null
null
null
up
4
sydney at totoche dot org
16 years ago
Instead of doing  :

<?php $strc = strcmp( strtolower($a[$f]), strtolower($b[$f]) ); ?>

you could do this :

<?php $strc = strcasecmp( $a[$f], $b[$f] ); ?>

which is more efficient and is does case insensitive comparison according to the current locale.
up
3
bo at erichsen dot com
21 years ago
when using usort to refer to a function inside a class i have succesfully used:

<?php usort($myarray,array($this,"cmp")); ?>
up
3
andi_mclean at ntlworld dot com
10 years ago
I needed a sort method that would sort strings but take note of any numbers and would compare them as number. I also want to ignore any non alphanumerical characters.

Eg.
Slot 1 Example
Slot 10 Example
Slot 2 Example

Should infact be
Slot 1 Example
Slot 2 Example
Slot 10 Example

<?php
function sort_with_numbers($a , $b) {
   
$a = explode(' ',$a);
   
$b = explode(' ',$b);
   
$size = min(count($a), count($b));
    for(
$index =0; $index < $size; ++$index) {
       
$a1 = ereg_replace("[^A-Za-z0-9]", "",$a[$index]);
       
$b1 = ereg_replace("[^A-Za-z0-9]", "",$b[$index]);
       
$equal = 0;
        if (
is_numeric($a1) && is_numeric($b1)) {
           
$equal = $a1 - $b1;
        } else {
           
$equal = strcasecmp($a1,$b1);
        }
        if (
$equal < 0) {
            return -
1;
        }
        if (
$equal > 0) {
            return
1;
        }
    }
    return
count($a) - count($b);   
}
?>
up
2
chris at candm dot org dot uk
3 years ago
In case anyone is interested, comparative timings over 100000000 runs
Based on comparing integers (500 and 501)
Spaceship:4
()?: operator:10
Subtraction:2

Based on comparing floats (500.1 and 501.3) (caveats noted)
Spaceship:5
()?: operator:9
Subtraction:3

Based on comparing strings ("five" and "four")
Spaceship:7
()?: operator:17
(Subtraction obviously not available)

Note: a dummy run was done with an empty loop and the elapsed time for this was subtracted from each of the above times so that they reflect ONLY the time to do the comparisons. As for significance. unless you are doing very large numbers of comparisons where spaceships are the order of the day, the difference is insignificant.
up
1
gus dot antoniassi at gmail dot com
3 years ago
This is a simple way to sort based on a "priority list":

<?php

$order
= [1,3,0,2];
$arr =   [
    [
'id' => 0 ],
    [
'id' => 1 ],
    [
'id' => 2 ],
    [
'id' => 3 ],
];

uasort(
   
$arr,
    function (
$a, $b) use ($order) {
        return
array_search($a['id'], $order) <=> array_search($b['id'], $order);
    }
);

print_r($arr);

?>

This will return:

Array
(
    [1] => Array
        (
            [id] => 1
        )

    [3] => Array
        (
            [id] => 3
        )

    [0] => Array
        (
            [id] => 0
        )

    [2] => Array
        (
            [id] => 2
        )

)

Note that if you have a value in $arr that is not on the $order list, you will need additional checks since the array_search function returns FALSE for undefined indexes.

官方地址:https://www.php.net/manual/en/function.usort.php

北京半月雨文化科技有限公司.版权所有 京ICP备12026184号-3