I have two multi-dimensional arrays and need to sort the first array in the same order as the second array based on different keys (but their values are the same). In the below example I need $allOptions
to be sorted into the same order as $regOptions
but based on the values of clID == optID
.
However, not all $allOptions
sub-arrays (clID) are present in $regOptions
sub-arrays (optID)....so any non-matched elements in $allOptions
would be thrown to the bottom/end of the array.
How can I do this?
$allOptions = array(
array("clID"=> 171, ...other values),
array("clID"=> 191, ...other values),
array("clID"=> 131, ...other values),
array("clID"=> 101, ...other values),
array("clID"=> 201, ...other values),
array("clID"=> 181, ...other values),
...
array("clID"=> 99, ...other values), // not in regOptions
array("clID"=> 129, ...other values) // not in regOptions
array("clID"=> 139, ...other values)
) ;
$regOptions = array(
array("order"=>1,"optID"=> 131, ...other values),
array("order"=>2,"optID"=> 191, ...other values),
array("order"=>3,"optID"=> 181, ...other values),
array("order"=>4,"optID"=> 139, ...other values),
array("order"=>5,"optID"=> 101, ...other values),
array("order"=>6,"optID"=> 201, ...other values),
array("order"=>7,"optID"=> 171, ...other values)
...
) ;
So the output would be:
$allOptions = array(
array("clID"=> 131, ...other values),
array("clID"=> 191, ...other values),
array("clID"=> 181, ...other values),
array("clID"=> 139, ...other values)
array("clID"=> 101, ...other values),
array("clID"=> 201, ...other values),
array("clID"=> 171, ...other values),
...
array("clID"=> 99, ...other values), // not in regOptions
array("clID"=> 129, ...other values) // not in regOptions
) ;
All earlier posted answers are working Waaaaaaaay too hard. Use array_column()
to generate a lookup array. Use usort()
or array_multisort()
to sort by that priority array.
Code: (Demo)
$priority = array_column($regOptions, 'order', 'optID');
usort(
$allOptions,
fn($a, $b) => ($priority[$a['clID']] ?? PHP_INT_MAX) <=> ($priority[$b['clID']] ?? PHP_INT_MAX)
);
var_export($allOptions);
If you want to fallback to sorting by clID ASC for all of the unmentioned clId values, then use the elvis operator to break those ties with a simple 3-way comparison on the column value.
$priority = array_column($regOptions, 'order', 'optID');
usort(
$allOptions,
fn($a, $b) =>
($priority[$a['clID']] ?? PHP_INT_MAX) <=> ($priority[$b['clID']] ?? PHP_INT_MAX)
?: $a['clID'] <=> $b['clID']
);
The first script can be performed with array_multisort()
in the following way. Note that this approach may perform better than usort()
because it makes fewer lookups, but it does sort on $priority
, then sort on $allOptions
row length, then clId
(how it would work if you called sort($allOptions)
; I imagine that the rows all have the same length though). (Demo)
$priority = array_column($regOptions, 'order', 'optID');
array_multisort(
array_map(fn($v) => $priority[$v['clID']] ?? PHP_INT_MAX, $allOptions),
$allOptions
);
var_export($allOptions);