Hon*_*ner 52 php arrays sorting multidimensional-array
我有一个数组数组:
Array (
[0] => Array (
[id] = 7867867,
[title] = 'Some Title'),
[1] => Array (
[id] = 3452342,
[title] = 'Some Title'),
[2] => Array (
[id] = 1231233,
[title] = 'Some Title'),
[3] => Array (
[id] = 5867867,
[title] = 'Some Title')
)
Run Code Online (Sandbox Code Playgroud)
需要按特定顺序进行:
我该怎么做呢?我之前已对数组进行了排序,并阅读了大量有关它的其他帖子,但它们始终是基于比较的(即valueA <valueB).
感谢帮助.
sal*_*the 109
您可以使用它usort()来精确地指示数组的排序方式.在这种情况下,$order阵列可以在比较功能中使用.
以下示例使用a closure来简化生活.
$order = array(3452342, 5867867, 7867867, 1231233);
$array = array(
array('id' => 7867867, 'title' => 'Some Title'),
array('id' => 3452342, 'title' => 'Some Title'),
array('id' => 1231233, 'title' => 'Some Title'),
array('id' => 5867867, 'title' => 'Some Title'),
);
usort($array, function ($a, $b) use ($order) {
$pos_a = array_search($a['id'], $order);
$pos_b = array_search($b['id'], $order);
return $pos_a - $pos_b;
});
var_dump($array);
Run Code Online (Sandbox Code Playgroud)
这项工作的关键是将要比较的值作为数组中ids 的位置$order.
比较函数通过在$order阵列中找到要比较的两个项的id的位置来工作.如果在数组$a['id']之前,那么函数的返回值将是负数(不那么"浮动"到顶部).如果在此之后,该函数返回一个正数(更大,因此"下沉").$b['id']$order$a$a['id']$b['id']$a
最后,使用封闭没有特殊原因; 这只是我快速编写这些一次性功能的首选方式.它同样可以使用普通的命名函数.
Sal*_*n A 16
为此附加要求扩展salathe的答案:
现在当我向数组中添加项而不是排序时会发生什么?我不关心它们出现的顺序,只要它出现在我指定的顺序之后.
您需要在排序功能中添加两个附加条件:
所以修改后的代码是:
$order = array(
3452342,
5867867,
7867867,
1231233
);
$array = array(
array("id" => 7867867, "title" => "Must Be #3"),
array("id" => 3452342, "title" => "Must Be #1"),
array("id" => 1231233, "title" => "Must Be #4"),
array("id" => 5867867, "title" => "Must Be #2"),
array("id" => 1111111, "title" => "Dont Care #1"),
array("id" => 2222222, "title" => "Dont Care #2"),
array("id" => 3333333, "title" => "Dont Care #3"),
array("id" => 4444444, "title" => "Dont Care #4")
);
function custom_compare($a, $b){
global $order;
$a = array_search($a["id"], $order);
$b = array_search($b["id"], $order);
if($a === false && $b === false) { // both items are dont cares
return 0; // a == b
}
else if ($a === false) { // $a is a dont care item
return 1; // $a > $b
}
else if ($b === false) { // $b is a dont care item
return -1; // $a < $b
}
else {
return $a - $b;
}
}
shuffle($array); // for testing
var_dump($array); // before
usort($array, "custom_compare");
var_dump($array); // after
Run Code Online (Sandbox Code Playgroud)
输出:
Before | After
-------------------------------+-------------------------------
array(8) { | array(8) {
[0]=> | [0]=>
array(2) { | array(2) {
["id"]=> | ["id"]=>
int(4444444) | int(3452342)
["title"]=> | ["title"]=>
string(12) "Dont Care #4" | string(10) "Must Be #1"
} | }
[1]=> | [1]=>
array(2) { | array(2) {
["id"]=> | ["id"]=>
int(3333333) | int(5867867)
["title"]=> | ["title"]=>
string(12) "Dont Care #3" | string(10) "Must Be #2"
} | }
[2]=> | [2]=>
array(2) { | array(2) {
["id"]=> | ["id"]=>
int(1231233) | int(7867867)
["title"]=> | ["title"]=>
string(10) "Must Be #4" | string(10) "Must Be #3"
} | }
[3]=> | [3]=>
array(2) { | array(2) {
["id"]=> | ["id"]=>
int(1111111) | int(1231233)
["title"]=> | ["title"]=>
string(12) "Dont Care #1" | string(10) "Must Be #4"
} | }
[4]=> | [4]=>
array(2) { | array(2) {
["id"]=> | ["id"]=>
int(5867867) | int(2222222)
["title"]=> | ["title"]=>
string(10) "Must Be #2" | string(12) "Dont Care #2"
} | }
[5]=> | [5]=>
array(2) { | array(2) {
["id"]=> | ["id"]=>
int(2222222) | int(1111111)
["title"]=> | ["title"]=>
string(12) "Dont Care #2" | string(12) "Dont Care #1"
} | }
[6]=> | [6]=>
array(2) { | array(2) {
["id"]=> | ["id"]=>
int(3452342) | int(3333333)
["title"]=> | ["title"]=>
string(10) "Must Be #1" | string(12) "Dont Care #3"
} | }
[7]=> | [7]=>
array(2) { | array(2) {
["id"]=> | ["id"]=>
int(7867867) | int(4444444)
["title"]=> | ["title"]=>
string(10) "Must Be #3" | string(12) "Dont Care #4"
} | }
} | }
Run Code Online (Sandbox Code Playgroud)
使用带有迭代调用方法的其他答案array_search()效率不高。通过重组/翻转“顺序”查找数组,您可以完全省略所有array_search()调用-使您的任务更加高效和简短。我将使用最现代的“太空飞船操作员”(<=>),但较早的技术在比较线中的作用相同。
方法1 - usort当所有的id值存在$order(演示)
$order=array_flip([3452342,5867867,7867867,1231233]); // restructure with values as keys, and keys as order (ASC)
// generating $order=[3452342=>0,5867867=>1,7867867=>2,1231233=>3];
$array=[
['id'=>7867867,'title'=>'Some Title'],
['id'=>3452342,'title'=>'Some Title'],
['id'=>1231233,'title'=>'Some Title'],
['id'=>5867867,'title'=>'Some Title']
];
usort($array,function($a,$b)use($order){
return $order[$a['id']]<=>$order[$b['id']];
// when comparing ids 3452342 & 1231233, the actual comparison is 0 vs 3
});
// uasort() if you want to preserve keys
var_export($array);
Run Code Online (Sandbox Code Playgroud)
方法2 - usort当一些id中不存在的值$order(演示)
*注意,isset()是不是更便宜的通话array_search()
$order=array_flip([3452342,5867867,7867867,1231233]); // restructure with values as keys, and keys as order (ASC)
// generating $order=[3452342=>0,5867867=>1,7867867=>2,1231233=>3];
$outlier=1+max($order);
// generating $outlier=4
$array=[
['id'=>7867867,'title'=>'Some Title'],
['id'=>3452342,'title'=>'Some Title'],
['id'=>'foo','title'=>'Some Title'],
['id'=>1231233,'title'=>'Some Title'],
['id'=>'bar','title'=>'Some Title'],
['id'=>5867867,'title'=>'Some Title']
];
usort($array,function($a,$b)use(&$order,$outlier){ // make $order modifiable with &
if(!isset($order[$a['id']])){$order[$a['id']]=$outlier;} // update lookup array with [id]=>[outlier number]
if(!isset($order[$b['id']])){$order[$b['id']]=$outlier;} // and again
return $order[$a['id']]<=>$order[$b['id']];
});
var_export($array);
Run Code Online (Sandbox Code Playgroud)
替代方法#2 - usort当一些id不存在的值$order
...我还想提一提,在某些情况下,避免在调用之前isset()充分准备$order数组比避免重复调用double 可能没有吸引力usort()。
这种单行代码将确保没有遗漏任何id值,从而消除了排序功能内部不需要比较行的任何其他问题。(完整的片段演示)
$order=array_replace(array_fill_keys(array_column($array,'id'),$outlier),$order);
Run Code Online (Sandbox Code Playgroud)
$dict = array_flip($order);
$positions = array_map(function ($elem) use ($dict) { return $dict[$elem['id']] ?? INF; }, $array);
array_multisort($positions, $array);
Run Code Online (Sandbox Code Playgroud)
当你的数组很大或者获取 id 的成本更高时,使用usort()可能会很糟糕,因为你会为每次比较重新计算 id。尝试array_multisort()使用预先计算的位置(参见下面的示例中mediumsort的 或fastsort),这并不复杂。
此外,在每次比较时在 order 数组中搜索 id(如在接受的答案中)并不会提高性能,因为每次比较都会对其进行迭代。计算一次。
在下面的代码片段中,您可以看到主要的三个排序函数:
slowsortmediumsortslowsort通过提前计算位置
进行改进fastsortmediumsort通过避免完全搜索
而得到改进。请注意,这些句柄元素的 id 不是通过提供后备值按顺序给出的INF。如果您的订单数组与原始数组的 id 1 对 1 匹配,那么请避免一起排序,只需将元素插入到正确的位置即可。我添加了一个函数cheatsort来完成这个任务。
更一般地,您可以按权重对数组进行排序(请参见weightedsort示例)。确保只计算一次重量,以获得良好的性能。
fastsort about 1 ms
mediumsort about 3 ms
slowsort about 60 ms
Run Code Online (Sandbox Code Playgroud)
提示:对于较大的数组,差异会变得更糟。
fastsort about 1 ms
mediumsort about 3 ms
slowsort about 60 ms
Run Code Online (Sandbox Code Playgroud)