如何按键前缀规则排序PHP对象数组并保留对象结构?
PHP对象数组按指定前缀排序并保留对象结构
问题背景
现有如下PHP对象数组:
$myWondersArray = [ (object)[ 'currentUnitDisplay' => 'WonderSkills: Starter Book 2, Unit 3 - Helping Mom (Part 1/3)', 'currentUnitPart' => 'wonderskills/starter_book_2/unit_3_helping_mom/part_1/', ], (object)[ 'currentUnitDisplay' => 'WonderSkills: Starter Book 2, Unit 3 - Helping Mom (Part 2/3)', 'currentUnitPart' => 'wonderskills/starter_book_2/unit_3_helping_mom/part_2/', ], (object)[ 'currentUnitDisplay' => 'WonderSkills: Starter Book 2, Unit 3 - Helping Mom (Part 3/3)', 'currentUnitPart' => 'wonderskills/starter_book_2/unit_3_helping_mom/part_3/', ], (object)[ 'previousUnitDisplay' => 'WonderSkills: Starter Book 2, Unit 2 - Sid\'s New Neighbors (Part 1/3)', 'previousUnitPart' => 'wonderskills/starter_book_2/unit_2_sids_new_neighbors/part_1/', ], (object)[ 'previousUnitDisplay' => 'WonderSkills: Starter Book 2, Unit 2 - Sid\'s New Neighbors (Part 2/3)', 'previousUnitPart' => 'wonderskills/starter_book_2/unit_2_sids_new_neighbors/part_2/', ], (object)[ 'previousUnitDisplay' => 'WonderSkills: Starter Book 2, Unit 2 - Sid\'s New Neighbors (Part 3/3)', 'previousUnitPart' => 'wonderskills/starter_book_2/unit_2_sids_new_neighbors/part_3/', ], (object)[ 'nextUnitDisplay' => 'WonderSkills: Starter Book 2, Unit 4 - Food from the Garden (Part 1/3)', 'nextUnitPart' => 'wonderskills/starter_book_2/unit_4_food_from_the_garden/part_1/', ], (object)[ 'nextUnitDisplay' => 'WonderSkills: Starter Book 2, Unit 4 - Food from the Garden (Part 2/3)', 'nextUnitPart' => 'wonderskills/starter_book_2/unit_4_food_from_the_garden/part_2/', ], (object)[ 'nextUnitDisplay' => 'WonderSkills: Starter Book 2, Unit 4 - Food from the Garden (Part 3/3)', 'nextUnitPart' => 'wonderskills/starter_book_2/unit_4_food_from_the_garden/part_3/', ], ];
需求:将数组中键以previous开头的对象排在最前,接着是键以current开头的对象,最后是键以next开头的对象,同时要保留对象本身结构不变,且每个分组内的原始顺序也需保留。
现有尝试的问题
之前尝试将对象拆分属性存入分组数组再合并,代码如下:
foreach($myWondersArray as $item => $value) { if($value->previousUnitDisplay){ array_push($previousArray, $value->previousUnitDisplay, $value->previousUnitPart) ; } } $completeWondersArray = array_merge($previousArray, $currentArray, $nextArray);
这种方式会把对象的属性拆成普通数组元素,直接丢失了原有的对象结构,无法满足需求。
解决方案
方案1:分组合并(直观易实现)
核心思路是直接将整个对象存入对应分组数组,而非拆分属性,最后合并三个分组数组即可。
// 初始化三个空分组数组 $previousGroup = []; $currentGroup = []; $nextGroup = []; // 遍历原数组,按对象属性前缀分组 foreach ($myWondersArray as $obj) { if (property_exists($obj, 'previousUnitDisplay')) { $previousGroup[] = $obj; } elseif (property_exists($obj, 'currentUnitDisplay')) { $currentGroup[] = $obj; } elseif (property_exists($obj, 'nextUnitDisplay')) { $nextGroup[] = $obj; } } // 按要求顺序合并数组 $sortedArray = array_merge($previousGroup, $currentGroup, $nextGroup);
这种方法逻辑清晰,每个分组内的原始顺序会被完整保留,且对象结构完全不变。
方案2:自定义排序函数(灵活扩展)
使用usort自定义排序规则,给不同前缀的对象分配权重,通过权重大小实现排序。PHP 7.0+ 版本的usort是稳定排序,同权重的对象会保留原始顺序。
usort($myWondersArray, function($a, $b) { // 定义权重:previous < current < next $weightMap = [ 'previous' => 0, 'current' => 1, 'next' => 2 ]; // 获取对象对应的前缀类型 $getType = function($obj) { if (property_exists($obj, 'previousUnitDisplay')) return 'previous'; if (property_exists($obj, 'currentUnitDisplay')) return 'current'; if (property_exists($obj, 'nextUnitDisplay')) return 'next'; return null; }; $aType = $getType($a); $bType = $getType($b); // 按权重差值排序 return $weightMap[$aType] - $weightMap[$bType]; });
排序完成后,$myWondersArray即为符合要求的数组,对象结构和分组内顺序均保留。
内容的提问来源于stack exchange,提问作者Liam
相关产品推荐
相关产品推荐

