奇葩的usort
如果两个成员比较结果相同,则它们在排序后的数组中的顺序居然是未定义的
Note: 如果两个成员比较结果相同,则它们在排序后的数组中的顺序未经定义。到 PHP 4.0.6 之前,用户自定义函数将保留这些单元的原有顺序。但是由于在 4.1.0 中引进了新的排序算法,结果将不是这样了,因为对此没有一个有效的解决方案。
如下例子:
我的本意是让$arr按key从大到小排序
例1:使用usort排序,结果key相等的元素位置受到影响
<?php
$arr = array(
array('key' => 0,'name' => '4'),
array('key' => 0,'name' => '5'),
array('key' => 0,'name' => '2'),
array('key' => 0,'name' => '3'),
array('key' => 1,'name' => '1'),
);
usort($arr, 'cmp');
function cmp($a, $b){
return ($a['key'] > $b['key']) ? -1 : 0;
}
var_export($arr);
输出为:
:!php test.php
array (
0 =>
array (
'key' => 1,
'name' => '1',
),
1 =>
array (
'key' => 0,
'name' => '3',
),
2 =>
array (
'key' => 0,
'name' => '2',
),
3 =>
array (
'key' => 0,
'name' => '5',
),
4 =>
array (
'key' => 0,
'name' => '4',
),
)
输出中key相等的元素的位置是随机的,但是,更加奇葩的是下面这个例子:
例2:
当我把$arr中key=1的元素放在第1个位置时,神奇的事发生了:
<?php
$arr = array(
array('key' => 1,'name' => '1'),
array('key' => 0,'name' => '4'),
array('key' => 0,'name' => '5'),
array('key' => 0,'name' => '2'),
array('key' => 0,'name' => '3'),
);
usort($arr, 'cmp');
function cmp($a, $b){
return ($a['key'] > $b['key']) ? -1 : 0;
}
var_export($arr);
输出为:
:!php test.php
array (
0 =>
array (
'key' => 0,
'name' => '3',
),
1 =>
array (
'key' => 0,
'name' => '2',
),
2 =>
array (
'key' => 0,
'name' => '5',
),
3 =>
array (
'key' => 0,
'name' => '4',
),
4 =>
array (
'key' => 1,
'name' => '1',
),
)
不仅key相等的元素位置受到影响,而且最大的key对应的元素也没有排在首位,Oh My LadyGaga!暂行的解决方案是使用array_multisort来排序:此方法类似SQL中的Order By,先按key降序排序,然后再按原始索引排序
<?php
$arr = array(
array('key' => 0,'name' => '4'),
array('key' => 0,'name' => '5'),
array('key' => 0,'name' => '2'),
array('key' => 0,'name' => '3'),
array('key' => 1,'name' => '1'),
);
$b = array();
$c = array();
$i = 0;
foreach($arr as $k => $v) {
$b[$k] = $v['key'];
$c[] = $i++;
}
array_multisort($b, SORT_NUMERIC, SORT_DESC, $c, SORT_ASC, $arr);
var_export($arr);
输出为:
:!php test.php
array (
0 =>
array (
'key' => 1,
'name' => '1',
),
1 =>
array (
'key' => 0,
'name' => '4',
),
2 =>
array (
'key' => 0,
'name' => '5',
),
3 =>
array (
'key' => 0,
'name' => '2',
),
4 =>
array (
'key' => 0,
'name' => '3',
),
)
当改变$arr中的元素位置时也不会影响到最终的排序结果。
Bingo!