phparrayssortingmultidimensional-arraycustom-sort

Sort single-column rows of a 2d array by string prefix in a custom order then by string suffix naturally; and re-apply original keys to result


I have a multidimensional array in this structure:

$arr = [
    0 => ['ref' => 'Q1'],
    1 => ['ref' => 'C6'],
    2 => ['ref' => 'C13'],
    3 => ['ref' => 'S3'],
    4 => ['ref' => 'Q11'],
    8 => ['ref' => 'S7'],
    9 => ['ref' => 'C4'],
];

I want to sort the array so that the order of values are S, Q, D, C, P, E and if possible have each alphanumeric ascending while also keeping the associate key [ref], like this:

$arr = [
    0 => ['ref' => 'S3'],
    1 => ['ref' => 'S7'],
    2 => ['ref' => 'Q1'],
    3 => ['ref' => 'Q11'],
    4 => ['ref' => 'C4'],
    8 => ['ref' => 'C6'],
    9 => ['ref' => 'C13'],
];

Solution

  • This code should do what you want. It uses usort with a compare function that first looks at the leading character and sorts that based on your specified order: S, Q, D, C, P, E. If the character is the same, it then compares the integer part of the value. Now the problem is that this loses the keys. We can't use uasort to get around that, as it will move the keys with the corresponding value. To get around that we first grab the keys of the array, then combine the keys with the sorted array at the end:

    function mysort($a, $b) {
        $sort_order = ['S', 'Q', 'D', 'C', 'P', 'E'];
        // first, sort by leading character
        $s = array_search($a['ref'][0], $sort_order) - array_search($b['ref'][0], $sort_order);
        if ($s != 0) return $s;
        // if the same, sort by numeric part
        return (int)substr($a['ref'], 1) - (int)substr($b['ref'], 1);
    }
    $keys = array_keys($arr);
    usort($arr, 'mysort');
    $arr = array_combine($keys, $arr);
    

    Output:

    Array
    (
        [0] => Array
            (
                [ref] => S3
            )
        [1] => Array
            (
                [ref] => S7
            )
        [2] => Array
            (
                [ref] => Q1
            )
        [3] => Array
            (
                [ref] => Q11
            )
        [4] => Array
            (
                [ref] => C4
            )
        [8] => Array
            (
                [ref] => C6
            )
        [9] => Array
            (
                [ref] => C13
            )
    )