0

我处于一个棘手的情况,我需要按位于其子数组中的值对数组进行排序,但我需要暂存结果。换句话说,排序应该由一个或多个优先级来完成。

问题是整个排序过程是由用户配置的,所以硬编码任何东西都不是一种选择。我需要保持灵活性,但我通过提供预定义的排序功能来限制选项。

让我们开始吧:

在此示例中,我们将对打印格式列表进行排序。我们将只使用两个可能的属性。

用户在 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 作为完整数组/对象进行比较是不正确的 - 正确的是比较这些数组中的特定值(函数应该比较的值)。

有关详细信息,请参阅接受的答案和相应的评论部分。

4

2 回答 2

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;
});
于 2013-03-21T10:55:54.780 回答
0

查看 php.net 手册中对 uasort 的注释 - http://php.net/manual/en/function.uasort.php

特别是 dholmes 发布的动态回调。

于 2013-03-21T11:01:33.250 回答