问题描述
我具有此功能,可以根据键输入对关联数组进行冒泡排序,并可以选择按降序或升序进行排序:
function bubbleSort($input,$key,$order){
while (true){
$end = false;
$swapped = false;
$idx = 0;
do {
$x = $input[$idx];
$y = $input[$idx + 1];
$x_param = $x[$key];
$y_param = $y[$key];
if (is_null($y)) {
$end = true;
continue;
}
if ($order == "desc"){
if ($x_param < $y_param){
$input[$idx] = $y;
$input[$idx + 1] = $x;
$swapped = true;
}
}
else{
if ($y_param < $x_param){
$input[$idx] = $y;
$input[$idx + 1] = $x;
$swapped = true;
}
}
$idx++;
}
while ($end == false);
if ($swapped == false) {break;}
}
return $input;
}
在此示例中,我将在关联数组上使用它:
$array = array(
array("Student Number" => 001,"Student name" => "David","Student age" => 21),array("Student Number" => 002,"Student name" => "Jonas","Student age" => 15),array("Student Number" => 003,"Student name" => "Katy","Student age" => 23));
如果我这样用print_r进行打印,它将成功排序并打印:
print_r(bubbleSort($array,"Student age","desc"));
问题是我得到注意:未定义的偏移量:3 包含 $ y = $ input [$ idx + 1];
以及注意:尝试为包含 $ y_param = $ y [$ key];
的行访问类型为null的值的数组偏移量它确实会打印正确排序的asc数组,因此代码可以正常工作。
Screenshot of the full output I get (with a lot of notices).
解决方法
您可以使用usort编写自己的比较函数。
<?php
$array = array(
array("Student Number" => 001,"Student name" => "David","Student age" => 21),array("Student Number" => 002,"Student name" => "Jonas","Student age" => 15),array("Student Number" => 003,"Student name" => "Katy","Student age" => 23)
);
function sort_array_by_key(&$array,$key,$order = 'ASC') {
usort(
$array,fn($a,$b) => $order == 'ASC'
? $a[$key] <=> $b[$key]
: $b[$key] <=> $a[$key]
);
}
sort_array_by_key($array,'Student name','DESC');
var_export($array);
输出:
array (
0 =>
array (
'Student Number' => 3,'Student name' => 'Katy','Student age' => 23,),1 =>
array (
'Student Number' => 2,'Student name' => 'Jonas','Student age' => 15,2 =>
array (
'Student Number' => 1,'Student name' => 'David','Student age' => 21,)
删除上升/下降部分以便于阅读:
function sort_array_by_key_asc(&$array,$key) {
usort(
$array,function($a,$b) use ($key) {
return $a[$key] <=> $b[$key];
}
);
}
(短箭头功能吸收了周围的范围,因此对作者来说可能不那么冗长。)
在usort联机帮助页中:
,注意:如果两个成员比较相等,则它们在 排序数组未定义。
注意:此函数将新键分配给数组中的元素。它会 删除可能已经分配的所有现有密钥,而不仅仅是 重新排序键。
解决未定义的索引。您需要检查它们是否存在。
所以代替:
$x = $input[$idx];
$y = $input[$idx + 1];
$x_param = $x[$key];
$y_param = $y[$key];
if (is_null($y)) {
$end = true;
continue;
}
您需要更多类似的东西:
if(!array_key_exists($idx + 1,$input)) {
$end = true;
continue;
}
$y = $input[$idx + 1];
$x_param = $x[$key];
$y_param = $y[$key];
但是,请注意,您没有检查其他键的有效性。并且假设您有一个从零开始的带有顺序索引的数字索引数组。因此,您可能需要进一步检查,或使用其他方式遍历数组。
array_multisort
冒泡方法的替代方法是使用array_multisort并依靠它来完成繁重的工作。
根据您选择的键提取一列值。然后可以使用该列的排序对父数组进行排序。
底层算法是一种快速排序(我相信)。这是使用SORT_REGULAR(默认值)作为比较。您将要查找排序标志。
<?php
$array = array(
'foo' => array("Student Number" => 001,'bar' => array("Student Number" => 002,'baz' => array("Student Number" => 003,"Student age" => 23)
);
function sort_by_key(&$array,$reverse = false) {
$column = [];
foreach($array as $v) {
$column[] = $v[$key] ?? null;
}
$order_flag = $reverse ? SORT_DESC : SORT_ASC;
array_multisort($column,$order_flag,$array);
}
sort_by_key($array,'Student age');
var_export($array);
输出:
array (
'bar' =>
array (
'Student Number' => 2,'foo' =>
array (
'Student Number' => 1,'baz' =>
array (
'Student Number' => 3,)
您总是会发现,如果您拥有相似的值,那么您可能想要进一步对另一列进行排序,依此类推。
您可以将上面的foreach换成array_column()调用,并在array_multisort中使用多个列。