I have two simple arrays. One is an array of posts ($posts) and the other is an array of post ID's that should be on top of the stream, like they are featured ($featured). I am trying to find an efficient way to loop through them and if an ID is in both arrays, move it to the beginning of the $posts array, and the ones that are moved should be sorted ASC by $featured['order'], so for example, some posts ($posts):
Array
(
[ab77] => Status_Update Object
(
[id] => ab77
[title] => Status Update
)
[b4k7] => Status_Update Object
(
[id] => b4k7
[title] => Status Update
)
[4d55] => Status_Update Object
(
[id] => 4d55
[title] => Status Update
)
[13c5] => Status_Update Object
(
[id] => 13c5
[title] => Status Update
)
[3aa2] => Status_Update Object
(
[id] => 3aa2
[title] => Status Update
)
)
and then some posts which should be featured ($featured):
Array
(
[13c5] => Array
(
[id] => 13c5
[order] => 1
)
[3a71] => Array
(
[id] => 3a71
[order] => 2
)
[4d55] => Array
(
[id] => 4d55
[order] => 3
)
)
So the $posts array should end up sorted like this:
13c5 4d55 ab77 bk47 3aa2
How do I do this without a bunch of slow loops?
2 Answers 2
This should be doable with uksort()
and closures:
uksort( $posts, function ( $a, $b ) use ( $featured ) {
$fa = ( isset( $featured[$a] ) ? $featured[$a]['order'] : INF );
$fb = ( isset( $featured[$b] ) ? $featured[$b]['order'] : INF );
if ( $fa != $fb ) return ( $fa < $fb ? -1 : +1 );
// could add a tie-breaker comparison here
return 0;
} );
-
That almost works, it returns the not-featured posts on top with the featured ones on the bottom but sorted correctly, like this:
ab77 bk47 3aa2 13c5 4d55
0pc0d3– 0pc0d32015年04月27日 22:13:10 +00:00Commented Apr 27, 2015 at 22:13 -
I'm trying to get to
13c5 4d55 ab77 bk47 3aa2
0pc0d3– 0pc0d32015年04月27日 22:14:38 +00:00Commented Apr 27, 2015 at 22:14 -
Strange. Can you show the exact code you're using? And maybe use
var_dump()
instead ofprint_r()
to display the arrays, so that there's no ambiguity about types?Ilmari Karonen– Ilmari Karonen2015年04月28日 00:24:19 +00:00Commented Apr 28, 2015 at 0:24
This is the messy answer I came up with works.
$found, $not_found = array();
foreach ($posts as $key => $value) {
if (array_key_exists($key, $featured)) {
$found[$key] = $value;
} else {
$not_found[$key] = $value;
}
}
usort($found, 'sort_by_order');
function sort_by_order ($a, $b) {
return $a['order'] - $b['order'];
}
$new = array_merge($found, $not_found);
array_key_exists('13c5', $featured))
etcuksort
to sort using a user-written comparison function. The function should check whether both keys are in the featured array usingarray_key_exists
. If they're both in or both not in, compare them with<
.