0

I have this function in my old php5 code that will accept a variable number of parameters and perform sorting based on the parameters:

function array_alternate_multisort(){
    $arguments = func_get_args();
    $arrays     = $arguments[0];
    for ($c = (count($arguments)-1); $c > 0; $c--)
    {
        if (in_array($arguments[$c], array(SORT_ASC , SORT_DESC)))
        {
                continue;
        }
        $compare = create_function('$a,$b','return strcasecmp($a["'.$arguments[$c].'"], $b["'.$arguments[$c].'"]);');
        usort($arrays, $compare);
        if ($arguments[$c+1] == SORT_DESC)
        {
                $arrays = array_reverse($arrays);
        }
    }
    return $arrays ;
}

I call it like this:

$alliances = array_alternate_multisort($alliances, "output", SORT_DESC, "score", SORT_DESC);

How can I replace this with a function without calling create_function()?

2
  • An alternate logic would be to use the usort function. On each invocation of callback you get two items and you need to compare the output for greater/lesser; if they're same then compare score and so on. Commented Jun 28, 2020 at 11:17
  • I must say the in_array() check is not very robust/reliable. If you were to sort an indexed array and wanted to pass a sorting rule for column 4, it would be considered SORT_DESC and completely skip that sorting rule. 3v4l.org/SpYYR Commented Jun 28, 2020 at 13:45

2 Answers 2

1

You can use an anonymous function instead:

$compare = function ($a, $b) use ($arguments, $c) {
    return strcasecmp($a[$arguments[$c]], $b[$arguments[$c]]);
};

Untested but should be close enough

The use keyword allows you to inherit variables from the parent scope inside your function.

Sign up to request clarification or add additional context in comments.

Comments

1

First of all, I'll argue that if you have the ability to hardcode this into your script:

$alliances = array_alternate_multisort($alliances, "output", SORT_DESC, "score", SORT_DESC);

then you can just as easily completely scrap your custom function and just write this:

Code: (Demo)

array_multisort(...[
    array_column($alliances, 'output'),
    SORT_DESC,
    array_column($alliances, 'score'),
    SORT_DESC,
    &$alliances
]);

This will do EVERYTHING that your custom function will do and more WITHOUT introducing ANY custom function.

This is a very concise, totally native, and instantly readable technique. Using this means that:

  • you will not confine your script to only SORT_ASC and SORT_DESC; there are other useful sorting flags to enjoy for specific scenarios.
  • you can opt to omit the sorting direction parameters if you wish to use SORT_ASC (the default sorting flag).
  • you modify the input array by reference like other native sorting functions.

Now anything beyond the above is going to introduce unnecessary convolution. To keep this hypothetical (which, again, I don't endorse) demonstration simple I'll insist that the sorting direction flags are required like in your original snippet.

Code: (Demo)

function array_alternate_multisort($array, ...$args) {
    foreach ($args as $i => $arg) {
        $sortParams[] = $i & 1 ? $arg : array_column($array, $arg);
    }
    $sortParams[] = &$array;
    array_multisort(...$sortParams);
    return $array;
}
  • & 1 is a bitwise odd check. If the index is odd, push the constant into $sortParams otherwise push the column data into $sortParams.

This answer belongs to a family of similar answers that use the splat operator to unpack parameters into a array_multisort() call.

Comments

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.