0

I am trying to sort an array (with both alphabetic and numeric keys) by keys where the alphabetic keys will come first alphabetically and then numeric keys numerically.

Tried ksort with all the available flags, however that didn't help. Tried several SO answers, but none of them served my purpose. Here is an example of the the array I have..

$array = array(
    'Bat' => array(),
    'Dog' => array(),
    'Apple' => array(),
    'Cat' => array(),
    1 => array(),
    3 => array(),
    2 => array(),
    4 => array()
);  

I need to sort it like this:

$array = array(
    'Apple' => array(),
    'Bat' => array(),
    'Cat' => array(),
    'Dog' => array(),
    0 => array(),
    1 => array(),
    2 => array(),
    3 => array()
);  

What I understand from a SO answer that it might need a custom function to sort using the usort function. That's where I am lost. Any help or guide to the proper direction will be appreciated.

Thanks

9
  • 1
    eval.in/1049257 Commented Aug 20, 2018 at 20:47
  • @splash58 The shortest solution. You should put that into an answer. Commented Aug 20, 2018 at 23:57
  • @splash58 I cannot reproduce the issue: sandbox.onlinephpfunctions.com/code/… Commented Aug 25, 2018 at 14:19
  • I'm not sure that understand how it works :) - eval.in/1050759 Commented Aug 25, 2018 at 14:37
  • @splash58 ...I should have used ksort() to explain... I can dream up a sample set that reproduces the improperly sorted output. sandbox.onlinephpfunctions.com/code/… Commented Aug 25, 2018 at 21:13

4 Answers 4

5

If you use only english alphabet and digits, usual ksort function works fine

ksort($array);
print_r($array);

demo

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

6 Comments

Strange. ksort was returning the numeric keys first when I tested. Thanks anyway.
Ha! Wish I would have read your answer before I bothered to write such a comprehensive answer (with a less efficient/direct snippet). Oh well, there's some valuable insights in it that future researchers may find helpful. Any clue why the OP's input array wasn't obeying ksort()?
@Abhik Does this not actually provide the desired result in your project? Can we see a more realistic representation of your project data? What php version are you on?
@mickmackusa I see two variants: problem XY or using non-english letters in real project.
@mickmackusa I am using PHP7.2. The ksort actually sorting the array both alphabetically and numerically. However, I needed alphabetic keys first, then numeric keys. The ksort was doing quite the opposite, it was returning the numeric keys first and then alphabetic keys.
|
3

As @splash58 states, ksort() is all that is required.

That said, if your project data is ordering numeric data before alphabetical and you need to reverse the order of those groups...

uksort() is the most direct/appropriate function for this job.

*Choose your key evaluating function carefully:

  • is_numeric() has a broad definition of what qualifies as true -- see the manual.
  • is_int() (and its alias is_integer()) is very strict in checking the data type. Importantly, a string key like "1" will evaluate to false.
  • ctype_digit(), while requiring all characters to be numeric, does not work on non-string type values. Importantly, a non-string key like 8 will evaluate to false.

If you are using php7, you can make good use the spaceship operator (<=>). If your php version is sub-7, you can use whatever old-skool comparison you like.

My solution allows the spaceship operator to order non-integers before integers, then sort those values ASC.

Code: (Demo)

$array = [
    2 => [],
    'Bat' => [],
    'Dog' => [],
    12 => [],
    'être' => [],
    'Cat' => [],
    1 => [],
    3 => [],
    'Apple' => [],
    4 => []
];

uksort($array, function ($a, $b) {
    return [is_int($a), $a] <=> [is_int($b), $b];
});

var_export($array);

The is_int() calls will return true or false. These are respectively compared as 1 and 0. Since sorting ASC, this means that false evaluations will come before true evaluations.

Output: (exactly the same as ksort())

2 Comments

You can do return $b <=> $a; because any "not-dogit" string is less then any digit ?
Hmm. I guess I didn't scope beyond the sample data. I didn't think that far.
2

Please don't mind the question. I have managed achieve bu using a custom function. I am posting the answer here to help if someone faces this issue.

function ev_sort_array( $array ) {
    $alp = array();
    $num = array();
    foreach ( $array as $key => $value ) {
        if ( is_numeric($key) ) {
            $num[$key] = $value;
        } else {
            $alp[$key] = $value;
        }
    }
    ksort( $alp );
    ksort( $num );

    return array_merge( $alp, $num );
}  

Thanks

Comments

2

You can use uksort this way:

$array = array(
'Bat' => array(),
'Dog' => array(),
'Apple' => array(),
'Cat' => array(),
1 => array(),
3 => array(),
2 => array(),
4 => array()
); 
uksort($array,function($a,$b){
    if(is_int($a)&&is_int($b)) return $a-$b;
    if(is_int($a)&&!is_int($b)) return 1;
    if(!is_int($a)&&is_int($b)) return -1;
    return strnatcasecmp($a,$b);
});
print_r($array);

the output is as expected:

Array
(
    [Apple] => Array
        (
        )

    [Bat] => Array
        (
        )

    [Cat] => Array
        (
        )

    [Dog] => Array
        (
        )

    [1] => Array
        (
        )

    [2] => Array
        (
        )

    [3] => Array
        (
        )

    [4] => Array
        (
        )

)

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.