【问题标题】:Multi-staged sorting of array based on subarray values using comparison functions使用比较函数基于子数组值对数组进行多阶段排序
【发布时间】:2013-03-21 10:42:32
【问题描述】:

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

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

让我们开始吧:

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

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

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

【问题讨论】:

    标签: php multidimensional-array comparison sorting usort


    【解决方案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;
    });
    

    【讨论】:

    • 哇,我什至不知道“使用”关键字。谢谢你。我会立即应用它,看看它是否适合我。
    • 在 PHP 5.3+ 中使用匿名函数。
    • 我应用了您的解决方案,但虽然它适用于一个排序属性,但似乎忽略了任何进一步的排序属性。我检查了很多次,但代码与您的描述相符。也许我错过了一些重要的东西?
    • 经过进一步测试,似乎该解决方案无法按预期工作,因为如果其中一个函数的结果不为零,它将永远不会应用多个排序函数。这可能适用于特定情况,但不适用于处理按降序或渐进值列表实际排序的多个排序函数..
    • 那么你的排序逻辑应该是什么?此功能在这里按主要和次要(以及第三等)标准排序。在具有名字和姓氏的示例中,仅当两个项目的名字相同时,它才按名字和姓氏排序。你还想应用什么其他逻辑?
    【解决方案2】:

    在 php.net 手册中查看 uasort 的 cmets - http://php.net/manual/en/function.uasort.php

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

    【讨论】:

    • 谢谢。这可能是由于我缺乏专业知识,但我不知道如何应用这些。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-02-14
    • 2021-01-13
    • 2019-07-23
    • 2011-09-25
    • 1970-01-01
    • 1970-01-01
    • 2020-03-29
    相关资源
    最近更新 更多