I’ve been cracking my brain trying to solve this challenge.
PHP default sort
function doesn’t provide the solution but still, using usort
isn’t easy either.
So this is what I’m trying to solve. I created an array in this order:
$data = array( '_', '@', ...range(-10, 10), ...range('A', 'Z'), ...range('a', 'z') )
Now I want to sort this array using usort
so that:
negative
numbers come first,uppercase
letters comes next_
&@
characters followslowercase
letters follows- Then finally
positive
numbers ends the order
Somewhat like:
/*
array(
"-10",
"-9",...
"A",
"B",...
"_",
"@", // @ may come first
"a",
"b",...
"1",
"2"...
) */
Is there any method available to solve this?
What I tried?
usort($data, function($a,$b) {
if( is_numeric($a) && (int)$a < 0 ) return -1; // take negative number to start
else {
if( !is_numeric($a) ) {
if( is_numeric($b) && (int)$b > 0 ) return -1;
else return $b < $a ? 1 : 0;
} else return 1; // take positive number to end
}
});
2
Answers
Think about is as a hierarchy. You have 5 non-overlapping "classes" that you want to sort: negative, uppercase, symbols, lowercase, positive. So first determine the class sort, and in the case that the class is the same for both items, compare their value instead.
Aside: Classes can be useful as ersatz namespaces to contain related functions and vars, so that you can box out the logic a bit better than something completely inline or dumping things in the local/global namespace.
Output:
Perhaps using regex will be harder for some developers to read/maintain and I didn’t bother comparing the performance, but it does afford some nice code brevity. Order a series of optional capture groups in the regex pattern. The regex engine will try to satisfy the earliest occurring subpattern and the remaining capture groups will not even be represented in the matches array (
$m[]
). Then, because PHP sorts arrays by their count before comparing the actual data, the entries in$m
which have the fewest elements will be ordered first byarray_multisort()
. This can, of course, be enhanced to respect multibyte strings using theu
pattern modifier.Code: (Demo)
More intuitive and easy to extend/maintain will be to use fallback comparisons with shorthand ternaries and spaceship operator comparisons until regular sorting is suitable.
Code: (Demo) (or Demo)
Alternatively, if performance is a concern, reduce the total number of required function calls by preparing arrays of evaluations, then call
array_multisort()
. (Demo)Related: