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


uksort() - single digit integers being treated as larger than double digit integers when first integer is smaller

正如问题所暗示的那样,我正在使用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
        )
  ……
)

您给出的结果是预期的,原因如下:

1. 您正在按降序排序:

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

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

2.你不对待平等:

关于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 上运行。

英国排序的替代品

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 上运行。

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

我不

认为这是在进行自然排序,我认为它只是将它们向后排序。至少在下面的测试中。并不是说这符合"答案"的条件,而是更多的数据。

$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 )