我在 PHP 中有以下数组,其中包含三角形 3 条边的长度:
$edge_lengths = array(
[0]=>
float(420)
[1]=>
float(593.9696961967)
[2]=>
float(420)
);
我现在需要对此数组进行排序,以便按相反顺序(从高到低)对值进行排序。如果有任何值匹配,则必须进一步按键以相反顺序(从高到低)对数组进行排序,以获得以下结果:
$edge_sorted = array(
[1]=>
float(593.9696961967)
[2]=>
float(420)
[0]=>
float(420)
);
在 Python 中,我可以用一行代码来完成此操作,如下所示:
edge_sorted = np.argsort(edge_lengths)[::-1]
然后将返回:
[1 2 0]
请注意,这仅返回索引列表;我不需要这样的积分。
我在 PHP 中尝试做同样事情的等效代码是这样的:
asort($edge_lengths, SORT_NUMERIC); // sort values in ascending order
$edge_lengths = array_reverse($edge_lengths, true); // reverse array and preserve keys
$edge_sorted = array();
foreach ($edge_sorted as $key => $value) {
$edge_sorted[] = $key;
}
此代码几乎有效,但在某些值相同的情况下,键仍然按从低到高排序,而不是从高到低排序。我考虑过尝试使用
usort
或 uksort
编写比较函数,但我不知道从哪里开始,希望得到一些帮助。
uksort
的自定义排序函数,首先根据该位置的值对键进行排序,然后(如果值相等)对键本身进行排序。然后,您可以使用 array_keys
获得与 argsort
相同的结果。
$edge_lengths = [420, 593.9696961967, 420];
uksort($edge_lengths, function($k1, $k2) use ($edge_lengths) {
$res = $edge_lengths[$k2] <=> $edge_lengths[$k1];
if ($res) return $res;
return $k2 <=> $k1;
});
print_r(array_keys($edge_lengths));
输出:
Array
(
[0] => 1
[1] => 2
[2] => 0
)
在 3v4l.org
进行演示没有一个 PHP 函数可以同时按键和值排序,您需要将输入转换为对数组,排序,然后将其转换回键控数组。
// you cannot directly compare floats and exect a sane answer
function float_compare($a, $b, $margin) {
return abs($a - $b) <= $margin;
}
function edgesort($edges, $margin=0.00000000001) {
$e = [];
foreach($edges as $k => $v) {
$e[] = [$k, $v];
}
usort($e, function($b, $a)use($margin){
if( ! float_compare($a[1], $b[1], $margin) ) {
return $a[1] <=> $b[1];
}
return $a[0] <=> $b[0];
});
$r = [];
foreach($e as $i) {
$r[$i[0]] = $i[1];
}
return $r;
}
$edge_lengths = [420, 593.9696961967, 420];
var_dump(edgesort($edge_lengths));
输出:
array(3) {
[1]=>
float(593.9696961967)
[2]=>
int(420)
[0]=>
int(420)
}
也就是说,如果您首先将值存储为
[edge_id, edge_length]
对,则会更简单。
从 PHP 8 开始,排序函数保证是稳定,所以你可以只对反向数组进行排序:
$edge_lengths = [420, 593.9696961967, 420];
$arr = array_reverse($edge_lengths, true);
arsort($arr);
print_r(array_keys($arr));
输出:
Array
(
[0] => 1
[1] => 2
[2] => 0
)