5
\$\begingroup\$

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;
}
\$\endgroup\$

2 Answers 2

2
\$\begingroup\$

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.

\$\endgroup\$
2
  • \$\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
    Commented 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\$ Commented Feb 1, 2023 at 19:07
4
\$\begingroup\$

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 only returns the value on its right, it also affords access to variables declared outside of the custom function's scope (previously use($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, or 1. 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:

\$\endgroup\$
1
  • 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\$ Commented Feb 2, 2023 at 0:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.