uksort() - 当第一个整数较小时,单个数字整数被视为大于双位整数

时间:2016-02-05 20:49:14

标签: php

正如问题所示,我使用uksort()从多维数组中获得所需的排序。

除了一个小缺陷外,一切都很好。我无法确切地传达问题所在,但它几乎就像natsort()被应用到某个地方而我无法弄清楚。

这是我的uksort()回调:

uksort($LoanPrograms, function($a, $b){
    $yearA = abs((int) filter_var($a, FILTER_SANITIZE_NUMBER_INT));
    $yearB = abs((int) filter_var($b, FILTER_SANITIZE_NUMBER_INT));

    return $yearB > $yearA ? 1 : -1;
});

我只是从字符串中提取数字(我已经三次检查)。数字看起来像这样:

$a - 30
$b - 5

$a - 20
$b - 10

$a - 30
$b - 15

$a - 7
$b - 10

但问题是,7被视为大于10,而5被视为大于30 ......等。

我无法弄清楚这里可能出现的问题。非常感谢任何想法。

修改

多维数组的快照:

Array
(
    [Conventional 15yr  Fixed] => Array
        (
            [0] => Array
                (
                    [HumanName] => Conventional 15yr  Fixed
                    [Rate] => 2.875
                )
        )
   [Conventional 20yr  Fixed] => Array
        (
            [0] => Array
                (
                    [HumanName] => Conventional 20yr  Fixed
                )
        )
   [Conventional 7/1 Arm] => Array
        (
            [0] => Array
                (
                    [HumanName] => Conventional 7/1 Arm
        )

  ……
)

2 个答案:

答案 0 :(得分:1)

您提供的结果有以下原因:

1。你正在降序排序:

return $yearB > $yearA ? 1 : -1;

要升序排序,您应该切换两个变量。请参阅下一点的手册中的引用。

2。你不能平等对待:

manual on uksort说回调函数(我强调):

  

如果第一个参数被认为分别小于,等于或者,则比较函数必须返回小于,等于,或大于的整数。大于第二个。

因此,最好只返回两个参数的数值差异。对于升序排序:

 return $yearA - $yearB;

3。加入多个数字组

具有分隔数字组的字符串可以提供意外值:例如" 7/1"将被消毒至71岁。

要解决此问题,您可以使用strpbrk代替filter_var:

function firstUnsignedInt($s) {
    return (int) strpbrk($s, "0123456789");
}

uksort($LoanPrograms, function($a, $b){
    // sort descending on first number in each string:
    return firstUnsignedInt($b) - firstUnsignedInt($a);
});

您可以在eval.in上看到此代码。

替代uksort

array_multisort函数允许对数组进行排序,方法是应用排序相同大小的另一个数组时发生的相同顺序更改。为此,我们可以使用带有提取的数值的数组:

function firstUnsignedInt($s) {
    return (int) strpbrk($s, "0123456789");
}

// Extract the numbers from all keys into a new array:
$terms = array_map('firstUnsignedInt', array_keys($LoanPrograms));
// Sort the numbers and let the original array follow the reordering:
array_multisort($terms, SORT_DESC, $LoanPrograms);

您可以在eval.in上看到此代码。

这可以使调试更容易,因为您可以使用提取的数字随时可用的数组。

答案 1 :(得分:0)

我没有看到它做的那种排序,我认为它只是向后排序。至少在以下测试中。并不是说它符合"答案",而是更多的数据。

$LoanPrograms = array("2" => "test", "10" => "test", "11" => "test", "1" => "test", "Conventional 15yr  Fixed" => "test", "Conventional 20yr  Fixed" => "test", "Conventional 7/1 Arm" => "test");

uksort($LoanPrograms, function($a, $b){
    $yearA = abs((int) filter_var($a, FILTER_SANITIZE_NUMBER_INT));
    $yearB = abs((int) filter_var($b, FILTER_SANITIZE_NUMBER_INT));

    echo $yearA . ' ? ' . $yearB . " = " . ($yearB > $yearA ? 1 : -1) . "<br />";

    return ($yearB > $yearA ? 1 : -1);
});

print_r($LoanPrograms);

给出:

 1 ? 10 = 1
1 ? 11 = 1
1 ? 2 = 1
1 ? 15 = 1
1 ? 20 = 1
71 ? 1 = -1
11 ? 10 = -1
20 ? 11 = -1
11 ? 71 = 1
11 ? 2 = -1
15 ? 11 = -1
10 ? 2 = -1
20 ? 15 = -1
71 ? 20 = -1
Array ( [Conventional 7/1 Arm] => test [Conventional 20yr Fixed] => test [Conventional 15yr Fixed] => test [11] => test [10] => test [2] => test [1] => test )