First and foremost, if your input array is the result set of a MySQL query, you should be sorting the data via an ORDER BY clause. FIELD()
is an excellent tool for the job, with slight weirdness that you need to reverse your sorting logic and write DESC
after the function.
Resource: https://www.electrictoolbox.com/mysql-order-specific-field-values/ (scroll down to "gotcha")
SQL Fiddle Demo: http://sqlfiddle.com/#!9/6b996f/1
Beyond that, I'll offer two refined versions of Nigel's and Eddie's solutions leveraging some php7+ goodness. Which one you choose to implement will have to do with:
- Whether you want to allow elements with duplicate
id
values to "survive" the process
- Which one performs more efficiently for your actual project data (the size of your input array and your custom order array)
- Personal preference (both snippets can be sensibly written in 3 to 5 lines, so brevity isn't much of a criteria)
PHP Demo
$array = [
(object)['id' => 8],
(object)['id' => 7],
(object)['id' => 5]
];
$order = [5, 8, 1]; // custom sort order
$order = array_flip($order); // restructure for easy lookup with isset()
$order[''] = max(array_column($array, 'id')) + 1; // append value higher than max for outlying ids
usort($array, function($a, $b) use ($order) {
return ($order[$a->id] ?? $order['']) <=> ($order[$b->id] ?? $order['']);
});
var_export($array);
*note that I could have passed $outlier
into the custom function scope as a second use
argument and replaced all of the $order['']
variables with $outlier
, but I opted to append the outlier data into the lookup array.
*I used parentheses in my custom function not only to improve readability, but to guarantee that the evaluation is performed as intended -- I didn't actually bother to check if the evaluation is the same without the parenthetical grouping.
Solution #2: array_replace() a flipped & filtered sort array with a keyed array
(PHP Demo)
$array = [
(object)['id' => 8],
(object)['id' => 7],
(object)['id' => 5]
];
$order = [5, 8, 1];
$order = array_flip($order); // flip for future key comparisons
$keyed = array_column($array, null, 'id'); // declare id values as new keys
$filtered_order = array_intersect_key($order, $keyed); // remove unwanted order keys
$replaced = array_replace($filtered_order, $keyed); // apply objects to output array
var_export(array_values($replaced)); // re-index the output (if desired)
*note this won't generate an oversized array of null
values and it will not remove values that are "falsey".
*I will again state that the use of array_column()
will damage the data if there are duplicate id
values in the input array.
usort()
.. – Calcite