I have a known hierarchy of the organization units, by descending order:
$hierarchy = [
"a" => "organization",
"b" => "company",
"c" => "group",
"d" => "unit",
"e" => "sub_unit",
"f" => "team"
];
I am then given an input key-value array which can consist of any of the units, but not necessarily all of them, and not always in the correct order:
$array = [
"team" => "team1",
"organization" => "organization1",
"group" => "group1"
];
I want to sort it in the correct order, so for the example input array above, the result should be:
$array = [
"organization" => "organization1",
"group" => "group1"
"team" => "team1"
];
The way I did it seem too complicated for what it's supposed to do, so maybe there is a better/more efficient way:
public function sort_custom(&$array)
{
// set the known hierarchy ordered alphabetically by the keys
$hierarchy = [
"a" => "organization",
"b" => "company",
"c" => "group",
"d" => "unit",
"e" => "sub_unit",
"f" => "team"
];
// fill temp array with the key-value pair from the matching input array
$tmp_array = [];
foreach ($array as $key => $value) {
$match = array_search($key, $hierarchy);
$tmp_array[$match] = $key;
}
// sort the temp array
ksort($tmp_array);
// assign the values from the original array to the temp array
foreach ($tmp_array as $key => $val) {
$tmp_array[$val] = $array[$val];
unset($tmp_array[$key]);
}
// finally copy the sorted temp array to the original array
$array = $tmp_array;
}
2 Answers 2
It is more optimal with this method.
function sort_custom(&$array)
{
// set the known hierarchy ordered alphabetically by the keys
$hierarchy = [
"organization", "company", "group", "unit", "sub_unit", "team"
];
$array = array_merge(
array_intersect_key(array_flip($hierarchy), $array),
$array
);
}
In this situation, it is not necessary to use an associative array, because with the array_flip function, the values will be replaced with keys.
-
\$\begingroup\$ This code works for me, thank you. Someone downvoted you though so I'm not sure why (I upvoted). I think they downvoted you because you didn't explain the code \$\endgroup\$pileup– pileup2023年02月01日 08:02:06 +00:00Commented Feb 1, 2023 at 8:02
-
1\$\begingroup\$ @B.DLiroy I'm guessing the downvote was due to the answer being very sparse in details, and acts as a code-dump of sorts. For example, how is this more optimal? Is it because the code is shorter? Why isn't it necessary to have an associative array? Just to be clear: I didn't downvote. \$\endgroup\$Ismael Miguel– Ismael Miguel2023年02月01日 19:07:35 +00:00Commented Feb 1, 2023 at 19:07
Much of your code does not need to exist. Even declaring letters to denote priority is unnecessarily tedious. You only need to establish a lookup array with your possible values then leverage that array inside of a uksort()
call. This would be the best use of a native PHP sorting function.
Code: (Demo)
function sort_custom(&$array)
{
$hierarchy = array_flip([
"organization",
"company",
"group",
"unit",
"sub_unit",
"team"
]);
uksort($array, fn($a, $b) => $hierarchy[$a] <=> $hierarchy[$b]);
}
$array = [
"team" => "team1",
"organization" => "organization1",
"group" => "group1"
];
sort_custom($array);
var_export($array);
uksort()
is a native sorting function that makes comparisons on the keys of the input array and the comparison logic is encapsulated in a custom function (user function).fn($a, $b) =>
is array function syntax which became available since PHP7.4. The$a
and the$b
parameters are two items (key strings in this case). It will be unknown what these strings will be or in what order the arguments will be delivered. It is common practice to use generic variable names for this reason. The=>
operator not onlyreturn
s the value on its right, it also affords access to variables declared outside of the custom function's scope (previouslyuse($hierarchy)
would have been required).$hierarchy[$a] <=> $hierarchy[$b])
accesses the related value (priority value) from the$hierarchy
(lookup) array for both$a
and$b
. The<=>
operator is the "three-way comparison operator" or "spaceship operator" -- it will evaluate two items and return either-1
,0
, or1
. The spaceship operator is built will some powerful evaluating behaviors so that numeric strings are evaluated as numbers and even arrays can be compared.
If you cannot guarantee that all possible keys will be listed in the lookup array, then you will need to establish a fallback priority value which is beyond the lowest priority value (assuming you'd want to have unlisted keys moved to the back of the array).
I feel like I've encountered this task before. Some relevant reading in no particular order:
- usort multisort array based on another array
- PHP make some of the Key to be sticky in an Associative array
- Sort array of strings by 3rd-to-last character based on another array then sort on whole strings
- Sort an array of numbers by another predefined, non-exhaustive array of number, then sort ascending
- Custom sort an associative array by its keys using a lookup array
- Array sort menu
- How to combine multiple array elements with common data?
- Get highest and lowest values from an array where order is like "AAA", "AA", "A", "BBB", "BB", etc
- Sorting Arrays of objects by predefined map of values
- Sorting a php array of arrays by custom order
-
1\$\begingroup\$ To improve your answer, I would just add a little explanation on what
fn($a, $b) => $hierarchy[$a] <=> $hierarchy[$b]
does (I know what it does, but O.P. seems to be a beginner in PHP) and add a small explanation on why most of the code isn't needed. Besides that, you provide a ton of examples. \$\endgroup\$Ismael Miguel– Ismael Miguel2023年02月02日 00:27:57 +00:00Commented Feb 2, 2023 at 0:27