PHP迭代程序自定义排序顺序(Laravel 4)


PHP Iterator Custom Sort Order (Laravel 4)

我有一个"Post"对象,通过IOC容器访问。各种错误告诉我,这个对象的类型最终是一个"Collection",它实现了几个接口,包括IteratorAggregate和ArrayAccess。

我想根据特定的顺序显示一组用户定义的帖子,例如:

$desired=array("69","63","70");//these represent post id's

以这种方式对数组进行排序似乎很复杂,但我想对我的集合进行排序。我一直在研究usort()、uksort()、Eloquent的sortBy()、array_multisort()的各种组合。。。但最明显的解的阶数是3,2,1或1,2,3,而不是2,1,3。

我离这个目标最近的一次是拿到我想要的,

//BlogController
private function myposts($desired){
    $posts=$this->post->whereIn('id',$desired)->get();
    ...

将Collection对象"转换"为数组

$posts=$posts->toArray();

并使用自定义函数处理阵列:源

function sortArrayByArray($array,$orderArray) {
    $ordered = array();
    foreach($orderArray as $key) {
        if(array_key_exists($key,$array)) {
            $ordered[$key] = $array[$key];
            unset($array[$key]);
        }
    }
    return $ordered + $array;
}
$sorted=sortArrayByArray($array1,$desired);

然后,我可以按正确的顺序vardump数组,但由于它现在是一个数组,我无法访问视图中的$posts对象。我可以将数组转换回post对象吗?

无论如何,整个方法都感觉很浪费,转换为数组后返回。。。是吗?有没有更直接的方法来对"集合"的内容进行排序?

这可能要好一点(一个本地php函数):

array_multisort($desired,$posts,SORT_STRING);
//only works with string keys
//$desire=(1,2,3) will not work!

同样,这适用于数组,但直接尝试"posts"对象失败。。。

最后,我发现使用Presenter:https://github.com/robclancy/presenter#array-在视图中工作的用法,在控制器中完成上述操作之一之后:

@foreach($posts as $post)
<?php $post=new PostPresenter($post) ?>
{{View::make('site.post.article')->with(compact('post'))}}
@endforeach

这终于奏效了,但感觉还有很长的路要走。有更好的方法来完成这项任务吗?一种方法与另一种方法的性能问题或最佳实践?提前感谢任何能够提供帮助的人。

您可以使用Collections自己的排序方法并传入回调。回调会比较集合中的每两个值,并"告诉"排序方法哪个值"更高"。排序方法然后对它们进行相应的排序。如果你想要一个特定的值顺序,你只需要创建映射并根据它进行排序。有关更多信息,请查看uasort

$posts->sort(function($a, $b){
    $desired=array("69" => 0,"63" => 1,"70" =>2);
    if(!array_key_exists($a,$desired) || !array_key_exists($b,$desired) || $a == $b){
        return 0
    }
    else{
        return ($desired[$a] < $desired[$b]) ? -1 : 1;
    }
});

除了@tim的答案,您还可以将排序后的数组重新分配给新的Collection对象:

$postsArray = $this->posts->toArray();
// Do some sorting/processing, then:
$newCollection = new 'Illuminate'Database'Eloquent'Collection( $postsArray );