如何对PHP二维数组按字母数字值排序?现有代码存问题
解决方案:按数字前缀+字母后缀排序PHP数组
这个问题我之前也碰到过,你需要的是**自然排序(人类排序)**的变种——先按数字前缀排序,数字相同的再按后面的字母后缀排序。你的原代码只提取了数字部分做比较,当然会忽略字母部分;另外usort的回调函数需要返回整数(-1/0/1),不是布尔值,这也是个容易踩的小坑。
完整实现代码
针对你的二维数组,我们可以用正则拆分数字和字母部分,分两步比较:
$array = [ ['id'=>1, 'name'=>1], ['id'=>2, 'name'=>2], ['id'=>3, 'name'=>'1b'], ['id'=>4, 'name'=>'1a'], ['id'=>5, 'name'=>4], ['id'=>6, 'name'=>7], ]; usort($array, function($a, $b) { // 用正则拆分数字前缀和字母后缀 preg_match('/^(\d+)(.*)$/', $a['name'], $matchesA); preg_match('/^(\d+)(.*)$/', $b['name'], $matchesB); // 转换数字部分为整数,方便比较 $numA = (int)$matchesA[1]; $numB = (int)$matchesB[1]; // 提取字母后缀(纯数字的话这里是空字符串) $strA = $matchesA[2]; $strB = $matchesB[2]; // 第一步:比较数字部分,升序排序 if ($numA != $numB) { return $numA - $numB; } // 第二步:数字相同时,按字母后缀的字典序排序 return strcmp($strA, $strB); }); // 验证排序结果 print_r($array);
针对对象数组的调整(适配你的原代码)
如果你处理的是对象数组(比如原代码里的$plots和getPlotNumber()方法),只需要把数组索引访问换成对象方法调用即可:
usort($plots, function($a, $b) { $nameA = $a->getPlotNumber(); $nameB = $b->getPlotNumber(); preg_match('/^(\d+)(.*)$/', $nameA, $matchesA); preg_match('/^(\d+)(.*)$/', $nameB, $matchesB); $numA = (int)$matchesA[1]; $numB = (int)$matchesB[1]; $strA = $matchesA[2]; $strB = $matchesB[2]; if ($numA != $numB) { return $numA - $numB; } return strcmp($strA, $strB); });
代码工作原理
- 正则拆分:用
/^(\d+)(.*)$/匹配每个name值,第一个捕获组提取开头的所有数字,第二个捕获组提取剩余的字符(字母或空)。 - 数字比较:把提取的数字转为整数,用
$numA - $numB返回排序所需的整数(负数表示$a在前,正数表示$b在前)。 - 字母比较:数字相同时,用
strcmp()比较后缀字符串,它会返回符合usort要求的整数,确保a在b前面,实现字典序排序。
内容的提问来源于stack exchange,提问作者Cleggy1012




