使用自定义排序顺序对数组排序,一个值为最后一个

时间:2011-08-19 02:25:46

标签: php arrays sorting multidimensional-array

我正在尝试对多维数组进行排序,并且总是在数组的末尾有一个值。数组应按'unitText'排序(不关心unitID是如何排序的),但始终将“Last”作为数组中的最后一个值。我几乎得到了它,但不是那里。

<?php

function cmp($a, $b)
{
    /*
    $a = preg_replace('@^(Last) @', '', $a);
    $b = preg_replace('@^(Last) @', '', $b);
    return strcasecmp($a, $b);
    */

    if(strtolower(substr($a['unitText'],0,4))=="last") return strnatcmp($a['unitText'],9999);
    else if(strtolower(substr($b['unitText'],0,4))=="last") return strnatcmp(9999,$b['unitText']);
    else return strnatcmp($a, $b);

    //return strnatcmp($a['unitText'], $b['unitText']);

    //return end($a) > end($b);

}

$unit = array(
    array("unitID"=>80, "unitText"=>"Q701"),
    array("unitID"=>30, "unitText"=>"H568"),
    array("unitID"=>25, "unitText"=>"Last"),
    array("unitID"=>40, "unitText"=>"Z255"),
    array("unitID"=>20, "unitText"=>"A459")
);

echo "<pre>";
print_r($unit);
echo "</pre>";

echo "<hr/>";

//uksort($unit['unitText'], "cmp");
//array_multisort($unit['unitText'], SORT_DESC, $unit['unitID'], SORT_ASC, $unit);
usort($unit, 'cmp');

echo "<pre>";
print_r($unit);
echo "</pre>";

?>

最终应该:

Array
(
    [0] => Array
        (
            [unitID] => 20
            [unitText] => A459
        )

    [1] => Array
        (
            [unitID] => 30
            [unitText] => H568
        )

    [2] => Array
        (
            [unitID] => 80
            [unitText] => Q701
        )

    [3] => Array
        (
            [unitID] => 40
            [unitText] => Z255
        )

    [4] => Array
        (
            [unitID] => 25
            [unitText] => Last
        )

)

我做错了什么?

2 个答案:

答案 0 :(得分:3)

你的问题在于这一行:

else return strnatcmp($a, $b);

请记住,$a$b都是数组,但strnatcmp()比较字符串。调用此函数时,您的两个数组将被隐式转换为字符串,这两个字符串的值都为Array,因此它们将返回相同的值并且不会被排序。

您应该比较unitText值:

else return strnatcmp($a['unitText'], $b['unitText'])

您没有看到这一点的事实告诉我,您的error_reporting级别在开发中没有设置得足够高,因为隐式转换在发生时会发出E_NOTICE。在开发过程中,您应始终设置error_reporting(E_ALL | E_STRICT);(在代码的入口点或php.ini中等),以便立即标记任何小问题以供您修复。

此外,当其中一个值为“Last”时,您根本没有理由调用strnatcmp(),因为您已经知道该值应该是最后一个。只需返回1-1(取决于哪个包含'最后')并完成它。

最后,您不需要代码中的所有else条件。由于所有路径都发出return,因此您可以假设if块之后的任何内容仅在比较失败时执行:

if (strtolower(substr($a['unitText'],0,4))=="last") {
  return 1;
}

if strtolower(substr($b['unitText'],0,4))=="last") {
  return -1;
}

return strnatcmp($a['unitText'], $b['unitText']);

在上面,如果我们在if内没有找到'Last',则只会执行第二个$a,因为如果函数已经结束,该函数就已经结束了。类似地,最后的return语句(带有strnatcmp()调用)仅在上述if条件都没有通过时执行,因为其中任何一个都会返回一个值并结束该函数。

这是一件小事,但嵌套了一堆不需要的ifelse块会降低代码的可读性。

答案 1 :(得分:0)

最后的比较比较a和b,它们都是数组。我收到了PHP警告:

PHP [警告] strnatcmp()期望参数1为字符串,给定数组

所有比较都可以这样简化:

if(strtolower(substr($a['unitText'],0,4))=="last") return 1;
else if(strtolower(substr($b['unitText'],0,4))=="last") return -1;
else return strnatcmp($a['unitText'], $b['unitText']);

你只需要为usort返回0,大于或小于零。