我处于一个棘手的情况,我需要通过其子阵列中的值对数组进行排序,但我需要将结果暂存。换句话说,排序应该由一个或多个优先级完成。
问题是整个排序过程可由用户配置,因此硬编码任何东西都不是一种选择。我需要保持灵活性,但我通过提供预定义的排序功能来限制选项。
让我们进入它:
在此示例中,我们将对打印格式列表进行排序。我们将只使用两种可能的属性。
用户在INI文件中配置排序过程:
sort_priority="special_deal:desc,ratio:asc"
说明
// special_deal -> This is a binary flag - if set to 1 the print format is a special deal and should therefore be presented first
// ratio -> This is the ratio of the given print format (i.e. 0.75 (that's a 3:4 format) or 1 (that's a 1:1 format))
在代码中,配置被分开:
$toSort=array(<OUR ARRAY WE WANT TO SORT>);
$sortKeys=explode(',', 'special_deal:desc,ratio:asc');
// we then iterate through the defined keys
foreach($sortKeys as $sortKey){
// we put together the name of the predefined sort function
if(strstr($sortKey, ':')) {
list($skey,$sdir)=explode(':', $sortKey);
$methodName='sort_by_'.$skey.'_'.$sdir;
} else $methodName='sort_by_'.$sortKey.'_asc';
// so $methodName can (for instance) be: sort_by_special_deal_asc
// or: sort_by_ratio_desc
// if the sort function is available, we apply it
if(is_callable($methodName))
usort($toSort, $methodName);
}
我们的排序功能如下:
function sort_by_special_deal_asc($a, $b){
return ($a['specialDeal']!=$b['specialDeal']);
}
function sort_by_special_deal_desc($a, $b){
return ($a['specialDeal']==$b['specialDeal']);
}
function sort_by_ratio_asc($a, $b){
if($a==$b) return 0;
return $a['ratio']<$b['ratio'] ? -1 : 1;
}
function sort_by_ratio_desc($a, $b){
if($a==$b) return 0;
return $a['ratio']>$b['ratio'] ? -1 : 1;
}
关于手头的问题......
上述解决方案工作正常,但仅适用于最后应用的排序函数。因此,当我们遍历要应用的排序函数时,每次调用 usort()都会导致重新排序数组中的所有元素。问题是,我们希望分类是分阶段(或堆叠),所以在这个给定的例子中,实际上意味着:
1.) Sort all entries so that the ones that are a special deal come first
2.) Then sort all entries by their ratio
以下是有关数据外观的示例:
$formats=array(
array(
'format' => '30x40',
'ratio' => 0.75
),
array(
'format' => '60x90',
'ratio' => 0.667
),
array(
'format' => '50x50',
'ratio' => 1
),
array(
'format' => '60x80',
'ratio' => 0.75,
'specialDeal' => 1
)
);
根据上述排序功能,所需的结果应:
$formats=array(
array(
'format' => '60x80',
'ratio' => 0.75,
'specialDeal' => 1
),
array(
'format' => '60x90',
'ratio' => 0.667
),
array(
'format' => '30x40',
'ratio' => 0.75
),
array(
'format' => '50x50',
'ratio' => 1
),
);
我希望这能正确解释这个问题。
有人能指出我正确的方向吗?如何使用 usort()动态地实现这一目标?
谢谢!
编辑:请注意 - 我的比较功能(见上文)有问题。有两个问题:
1。)返回布尔值是错误的 - 返回-1,0或1是要走的路。 2.)$ a和$ b作为完整数组/对象的比较不正确 - 正确的是比较这些数组中的特定值(函数应该比较的那些)。
有关详细信息,请参阅接受的答案和相应的评论部分。
答案 0 :(得分:1)
通过解析用户的排序首选项来构建这样的数组:
$sortMethods = array('sort_by_ratio_desc', 'sort_by_special_deal_asc');
然后使用这样的比较排序:
usort($array, function ($a, $b) use ($sortMethods) {
foreach ($sortMethods as $method) {
$result = $method($a, $b);
if ($result != 0) {
break;
}
}
return $result;
});
答案 1 :(得分:0)
在php.net手册中查看uasort的评论 - http://php.net/manual/en/function.uasort.php
特别是由dholmes发布的动态回调版。