根据特定字符后面的子字符串对数组进行排序,然后按字符之前的子字符串对数组进行排序


Sort array based on substring following a specific character, then by the substring before the character

我需要按"R"后面的数字重新排序数组中的元素,然后是第一部分。

我有一个包含以下元素的数组。

215/75R17.5
235/75R17.5
8.25R16
7.00R16
11R22.5
7.50R16

所以到这个:

7.00R16
7.50R16
8.25R16
11R22.5
215/75R17.5
235/75R17.5
首先,

这显然是一个自定义比较; 其首选函数是 usort ,它接受自定义比较作为参数。

自定义比较函数如下所示:

function customCompare($x, $y) {
    $x = explode('R', $x);
    $y = explode('R', $y);
    if ($x[1] != $y[1]) return $x[1] < $y[1] ? -1 : 1;
    return strnatcmp($x[0], $y[0]);
}

看到它的实际效果

工作原理

首先,我们在字符R上拆分每个输入字符串,从'8.25R16'这样的字符串中生成一个数组,如['8.25', '16']。在每个数组中,第二个元素是直径(第一个排序标准),第一个元素是宽度(第二个标准)。

如果直径不同,那么我们立即根据此做出判断。

如果直径相等,那么我们使用strnatcmp来比较宽度 - 这样宽度 100 大于宽度 20(愚蠢的 ASCII 比较会产生相反的结果)。

无论你决定如何隔离R后面的子字符串,你都应该尽量减少函数调用的次数。

array_multisort()与隔离技术的映射调用一起使用将比usort()方法执行得更好,因为usort()将在同一值上多次执行隔离技术。

在下面的代码段中,我在隔离时不会删除R,因此我使用自然排序来正确比较数字子字符串。 如果您不熟悉strpbrk()请参阅此答案以进行演示。

代码:(演示)

$array = [
    '215/75R17.5',
    '235/75R17.5',
    '8.25R16',
    '7.00R16',
    '11R22.5',
    '7.50R16'
];
array_multisort(array_map(fn($v) => strpbrk($v, 'R'), $array), SORT_NATURAL, $array);
var_export($array);
<小时 />

纯粹隔离数值的方法不需要自然排序。(演示)

array_multisort(array_map(fn($v) => sscanf($v, '%*[^R]R%f')[0], $array), $array);
var_export($array);