我需要按分数排序一个项目数组,然后按日期排序,而不移动锁值大于零的行。
换句话说,在排序完成后,带有lock=3和lock=5的行应该保持在相同/原始的位置。
[
['id' => 7867867, 'lock' => 0, 'score' => 322, 'strtotime' => 16614713],
['id' => 7867867, 'lock' => 0, 'score' => 444, 'strtotime' => 16614613],
['id' => 7867867, 'lock' => 3, 'score' => 0, 'strtotime' => 16613713],
['id' => 7867867, 'lock' => 0, 'score' => 11, 'strtotime' => 16612713],
['id' => 7867867, 'lock' => 5, 'score' => 0, 'strtotime' => 16614413],
['id' => 7867867, 'lock' => 0, 'score' => 42, 'strtotime' => 16614113],
['id' => 7867867, 'lock' => 0, 'score' => 22, 'strtotime' => 16614013],
]我使用下面的代码对score进行排序,而不是在strtotime上排序,但这会影响不应该移动的行。
usort($array, function ($a, $b) {
if ( $a->score == $b->score ) { //score are same
return $b->strtotime <=> $a->strtotime; //sort by strtotime
}
return $b->score <=> $a->score; //else sort by score
});我想要的输出是:
[
['id' => 7867867, 'lock' => 0, 'score' => 11, 'strtotime' => 16612713],
['id' => 7867867, 'lock' => 0, 'score' => 22, 'strtotime' => 16614013],
['id' => 7867867, 'lock' => 3, 'score' => 0, 'strtotime' => 16613713],
['id' => 7867867, 'lock' => 0, 'score' => 42, 'strtotime' => 16614113],
['id' => 7867867, 'lock' => 5, 'score' => 0, 'strtotime' => 16614413],
['id' => 7867867, 'lock' => 0, 'score' => 322, 'strtotime' => 16614713],
['id' => 7867867, 'lock' => 0, 'score' => 444, 'strtotime' => 16614613],
]发布于 2022-08-26 00:54:23
在排序过程中,您无法访问列表中的绝对位置,只有要比较的一对项,因此我将这样处理它:
对于步骤1,只需遍历数组,生成两个新数组:
$result = [];
$locked = [];
foreach ( $input as $item ) {
if ( $item['lock'] > 0 ) {
$locked[] = $item;
}
else {
$result[] = $item;
}
}步骤2是您已经拥有的代码,它使用了解锁项数组(我称之为$result ),因为它最终将包含最终结果。
对于第三步,您可以使用接合在选定的位置将一个项放入数组中,然后将所有内容向下移动。
这里需要注意的一点是,您在事项中插入的顺序是:如果您将项目X插入位置5,则将项目Y移至位置3,则位置X将向前移至位置6。因此,如果锁定的项目尚未排序,请对它们进行排序:
usort($locked, fn($a,$b) => $a['lock'] <=> $b['lock']);然后绕过去,把它们拼接到他们想要的位置上:
foreach ( $locked as $item ) {
array_splice($result, $item['lock'], 0, $item);
}然后你就应该完成:)
发布于 2022-08-27 10:58:20
在没有任何过滤、临时数组或剪接的情况下,我已经构建了一个手动排序算法,其中包含三个嵌套循环(具有最佳性能的条件短路),以提供“粘性排序”。
没有函数调用,因此它将执行得相当快。我添加了内联注释以帮助理解代码。
下面的代码段并不关心非零锁值是什么。在发布的问题中,锁定的行已经位于结果中它们应该位于的位置。该算法从不移动具有非零锁值的行。这使得脚本很容易适应另一个标志指示“固定行”的其他场景。
代码:(演示)
$maxIndex = count($array) - 1;
for ($a = 0; $a < $maxIndex; ++$a) {
if ($array[$a]['lock'] !== 0) {
continue; // cannot move locked row
}
for ($b = 0; $b < $maxIndex; ++$b) {
if ($array[$b]['lock'] !== 0) {
continue; // cannot move locked row
}
// find next movable row
for ($c = $b + 1; $c <= $maxIndex; ++$c) {
if ($array[$c]['lock'] === 0) {
break; // $c is index of non-locked row
}
}
if ($c > $maxIndex) {
break; // no more movable rows
}
// sort movable rows
if (
$array[$b]['score'] > $array[$c]['score']
|| ($array[$b]['score'] === $array[$c]['score']
&& $array[$b]['strtotime'] > $array[$c]['strtotime'])
) {
[$array[$b], $array[$c]] = [$array[$c], $array[$b]];
}
}
}
var_export($array);https://stackoverflow.com/questions/73494836
复制相似问题