我有以下数组:
$array = [
'z' => 2,
'd' => 1,
'a' => 2,
];
现在我想按值(整数)排序,然后根据键是否在该白名单中进行排序:
$allowlist = ['a', 'd'];
所以我做了以下事情:
arsort($array);
uksort($array, function($a, $b) {
return in_array($a, $allowlist) ? -1 : 1;
});
但这会返回:
[d]: 1
[a]: 2
[z]: 2
我真正想要的是首先对值进行排序,然后如果存在平局断路器,则根据其是否在该允许列表中对键进行排序,这应该导致以下结果:
[a]: 2
[z]: 2
[d]: 1
您可以使用
uksort
为您提供键,并且您可以将 $array
传递到排序函数中以访问该值。
$array = [
'a' => 2,
'z' => 2,
'd' => 1
];
$allowlist = ['a', 'd'];
uksort(
$array,
static function($a, $b) use ($array, $allowlist) {
if($array[$a] === $array[$b]) {
return in_array($a, $allowlist) ? -1 : 1;
}
return $array[$b] <=> $array[$a];
}
);
这受到了这个答案的启发:https://stackoverflow.com/a/65315474/231316
我建议尽可能少地进行评估和函数调用。
我的代码片段中故意有两个宇宙飞船运算符——这意味着
in_array()
调用仅在必要时执行。宇宙飞船运算符将处理排序规则数组,但这会降低效率,因为每次迭代都会调用所有 in_array()
函数。不要使用这个演示。
代码:(演示)
uksort(
$array,
fn($a, $b) =>
$array[$b] <=> $array[$a] // sort values DESC
?: in_array($b, $allowlist) <=> in_array($a, $allowlist) // sort keys with priority given to whitelisted keys
);
var_export($array);
按值降序排序,然后通过检查
in_array()
是否降序来打破平局。对布尔结果进行排序时,降序将 true 放在 false 之前。
如果您正在处理大型数组,那么我会敦促您避免
in_array()
。相反,翻转查找数组并在自定义函数中使用 isset()
。
自定义函数的可见级联规则语法使其易于阅读和扩展。如果您想在两个或两个键均未列入白名单时添加另一个决胜局,则只需使用新规则添加另一行即可:
?: $a <=> $b // sort by key ascending (alphabetically)
该键使用按键上的
array_flip
功能。这给 uksort
一个可以比较的值:
$array = [
'a' => 2,
'z' => 2,
'd' => 1,
'e' => 1,
];
$allowlist = array_flip(['a', 'e', 'd']);
uksort(
$array,
static function($a, $b) use ($array, $allowlist) {
if ($array[$a] === $array[$b]) {
if (!key_exists($a,$allowlist) || !key_exists($b,$allowlist)) {
return 0;
}
return $allowlist[$a] <=> $allowlist[$b];
}
return $array[$b] <=> $array[$a];
}
);
echo '<pre>'.print_r($array,1).'</pre>';
结果:
Array
(
[a] => 2
[z] => 2
[e] => 1
[d] => 1
)