First I sort the items in the array by score, then I sort the items with the same score by date. However, while doing this sorting, I want a lock value greater than 0 to represent the position that item should end up in. For example: if the lock value is 5, I want it to stay in the fifth row in the array.
Here code sample...
[0] => Array (
[id] = 7867867,
[sort] = 1,
[lock] = 0,
[score] = 322,
[strtotime] = 16614713),
[1] => Array (
[id] = 7867867,
[sort] = 2,
[lock] = 0,
[score] = 444,
[strtotime] = 16614613),
[2] => Array (
[id] = 7867867,
[sort] = 3,
[lock] = 3,
[score] = 0,
[strtotime] = 16613713),
[3] => Array (
[id] = 7867867,
[sort] = 4,
[lock] = 0,
[score] = 11,
[strtotime] = 16612713),
[4] => Array (
[id] = 7867867,
[sort] = 5,
[lock] = 5,
[score] = 0,
[strtotime] = 16614413),
[5] => Array (
[id] = 7867867,
[sort] = 6,
[lock] = 0,
[score] = 42,
[strtotime] = 16614113),
[6] => Array (
[id] = 7867867,
[sort] = 7,
[lock] = 0,
[score] = 22,
[strtotime] = 16614013),
);
PHP Code If there is a method other than Usort, please write.
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
});
Output
[0] => Array (
[id] = 7867867,
[sort] = 2,
[lock] = 0,
[score] = 444,
[strtotime] = 16614613),
[1] => Array (
[id] = 7867867,
[sort] = 1,
[lock] = 0,
[score] = 322,
[strtotime] = 16614713),
[2] => Array (
[id] = 7867867,
[sort] = 6,
[lock] = 0,
[score] = 42,
[strtotime] = 16614113),
[3] => Array (
[id] = 7867867,
[sort] = 7,
[lock] = 0,
[score] = 22,
[strtotime] = 16614013),
[4] => Array (
[id] = 7867867,
[sort] = 4,
[lock] = 0,
[score] = 11,
[strtotime] = 16612713),
[5] => Array (
[id] = 7867867,
[sort] = 5,
[lock] = 5,
[score] = 0,
[strtotime] = 16614413),
[6] => Array (
[id] = 7867867,
[sort] = 3,
[lock] = 3,
[score] = 0,
[strtotime] = 16613713),
);
What I want to do:
[0] => Array (
[id] = 7867867,
[sort] = 2,
[lock] = 0,
[score] = 444,
[strtotime] = 16614613),
[1] => Array (
[id] = 7867867,
[sort] = 1,
[lock] = 0,
[score] = 322,
[strtotime] = 16614713),
[2] => Array (
[id] = 7867867,
[sort] = 3,
[lock] = 3,
[score] = 0,
[strtotime] = 16613713),
[3] => Array (
[id] = 7867867,
[sort] = 6,
[lock] = 0,
[score] = 42,
[strtotime] = 16614113),
[4] => Array (
[id] = 7867867,
[sort] = 7,
[lock] = 0,
[score] = 22,
[strtotime] = 16614013),
[5] => Array (
[id] = 7867867,
[sort] = 5,
[lock] = 5,
[score] = 0,
[strtotime] = 16614413),
[6] => Array (
[id] = 7867867,
[sort] = 4,
[lock] = 0,
[score] = 11,
[strtotime] = 16612713),
);
Is there a way to do this?
CodePudding user response:
During a sort, you have no access to the absolute position in the list, only the pair of items being compared, so I would approach it this way:
- Take the "locked" values out of the list
- Sort everything else
- Put the locked values back in
For step 1, just loop over array, producing two new arrays:
$result = [];
$locked = [];
foreach ( $input as $item ) {
if ( $item['lock'] > 0 ) {
$locked[] = $item;
}
else {
$result[] = $item;
}
}
Step 2 is the code you already have, using the array of unlocked items, which I've called $result
, because it will eventually contain the final result.
For step 3, you can use array_splice to put an item into the array at a chosen position, shifting everything afterwards down.
An important thing to note here is that the order you insert in matters: if you insert item X into position 5, then item Y into position 3, position X will be shifted forward to position 6. So if your locked items aren't already in order, sort them:
usort($locked, fn($a,$b) => $a['lock'] <=> $b['lock']);
Then loop over, and splice them into their desired positions:
foreach ( $locked as $item ) {
array_splice($result, $item['lock'], 0, $item);
}
And then you should be done :)