在关联数组上使用冒泡排序时未定义的偏移量

Undefined offset when using bubble sort on associative array

我有这个函数可以根据键输入对关联数组进行冒泡排序,并可以选择按降序或升序排序:

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];[=35 的行=]

以及 注意:尝试访问包含 $y_param = $y[$ 的行的 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,
  ),
)

删除 ascending/descending 部分以便于阅读:

function sort_array_by_key_asc(&$array, $key) {
    usort(
        $array, function($a, $b) use ($key) {
            return $a[$key] <=> $b[$key];
        }
    );
}

(短箭头函数吸收周围范围,因此作者可以不那么冗长。)

来自 usort 联机帮助页:

Note: If two members compare as equal, their relative order in the sorted array is undefined.

Note: This function assigns new keys to the elements in array. It will remove any existing keys that may have been assigned, rather than just reordering the keys.

解决您未定义的索引。您需要检查它们是否存在。

所以代替:

        $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, "Student name" => "David", "Student age" => 21),
    'bar' => array("Student Number" => 002, "Student name" => "Jonas", "Student age" => 15),
    'baz' => array("Student Number" => 003, "Student name" => "Katy", "Student age" => 23)
);

function sort_by_key(&$array, $key, $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,
    'Student name' => 'Jonas',
    'Student age' => 15,
  ),
  'foo' => 
  array (
    'Student Number' => 1,
    'Student name' => 'David',
    'Student age' => 21,
  ),
  'baz' => 
  array (
    'Student Number' => 3,
    'Student name' => 'Katy',
    'Student age' => 23,
  ),
)

您总是会发现,如果您有相似的值,您可能会想要在另一列上进一步排序,依此类推。

您可以将上面的 foreach 替换为 array_column() 调用,并在 array_multisort.

中使用多个列

How can I sort arrays and data in PHP?