phparrayssortingusortcustom-sort

Sort delimited array values by first half ascending then by second half descending


I am trying to sort my array values with sizes but the result is not as I expected. This is my code:

function cmp($a, $b) {
    $sizes = array(
        "XS" => 0,  
        "S" => 1,
        "M" => 2,
        "L" => 3,
    );

    $size_a = explode("_", $a)[1];
    $size_b = explode("_", $b)[1];

    return $sizes[$size_a] <=> $sizes[$size_b];
}
    
$array = array("GL001_M","GL001_XS","GL001_S",                  
                "GL001_L","GL002_M","GL002_XS",
                "GL002_S","GL002_L");

usort($array,"cmp");

foreach($array as $arrayItem){
    echo $arrayItem.' | ';
}

My output is this:

GL001_XS | GL002_XS | GL001_S | GL002_S | GL001_M | GL002_M | GL001_L | GL002_L | 

Instead I would like this:

GL001_XS | GL001_S | GL001_M | GL001_L | GL002_XS | GL002_S | GL002_M | GL002_L | 

Solution

  • The issue with the current method is that it only sorts on the final part of each string (so the 'S', 'XS' etc.)

    What you can do is expand the comparison to sort on the first part ('GL001') and only when there is a match to use the size to sort them.

    $size_a = explode('_', $a);
    $size_b = explode('_', $b);
    
    return ($size_a[0] <=> $size_b[0]) ?: $sizes[$size_a[1]] <=> $sizes[$size_b[1]];
    

    So $size_a[0] <=> $size_b[0] will compare the 'GL001' bits.

    The using ?: it will return the second part if the value of the first part is 0 (i.e. they are the same).
    $sizes[$size_a[1]] will be the size translated by the array (so 'S' => 1).