php sort array using the keys of months disregard other key

Viewed 81
Array
(
    [strMachineGroupID] => MC000027
    [strMachineGroup] => 1
    [April-201904_QTY] => 1
    [February-201902_QTY] => 1
    [January-201901_QTY] => 1
    [July-201907_QTY] => 1
    [June-201906_QTY] => 1
    [March-201903_QTY] => 1
    [May-201905_QTY] => 1
    [strMachineGroupIDUE] => MC000027
    [April-201904_UE] => 1.00
    [February-201902_UE] => 1.00
    [January-201901_UE] => 1.00
    [July-201907_UE] => 1.00
    [June-201906_UE] => 1.00
    [March-201903_UE] => 1.00
    [May-201905_UE] => 1.00
)

This one my array in my query result. I wanted to sort this array so that the result will be show index in monthly order(january to december).

I want that january ill be next to each other as well as other months.

I tried using:

    //     $value = (array)$value;
    //     print_r($value);
    //     print_r(asort($value));
    //     print_r(krsort($value));
    //     print_r(ksort($value)); 

But they did work. Im still working on this one.

Any idea that does this will really help.

5 Answers

You need to use uksort to compare the keys. This callback function will sort keys with a date to the beginning (relying on the fact that those keys have a 6 digit YYYYMM string in them) and then sort between dates. Non-date keys are sorted alphabetically.

uksort($array, function ($k1, $k2) {
    if (preg_match('/^\w+-(\d{6})_\w+$/', $k1, $m1)) {
        if (preg_match('/^\w+-(\d{6})_\w+$/', $k2, $m2)) {
            // both have dates, sort on that
            return strcmp($m1[1], $m2[1]);
        }
        else {
            // dates sort first
            return -1;
        }
    }
    elseif (preg_match('/^\w+-(\d{6})_\w+$/', $k2, $m2)) {
        // dates sort first
        return 1;
    }
    else {
        // neither is a date, sort alphabetically
        return strcmp($k1, $k2);
    }
});

Output:

Array (
    [January-201901_UE] => 1
    [January-201901_QTY] => 1
    [February-201902_QTY] => 1
    [February-201902_UE] => 1
    [March-201903_UE] => 1
    [March-201903_QTY] => 1
    [April-201904_UE] => 1
    [April-201904_QTY] => 1
    [May-201905_UE] => 1
    [May-201905_QTY] => 1
    [June-201906_QTY] => 1
    [June-201906_UE] => 1
    [July-201907_UE] => 1
    [July-201907_QTY] => 1
    [strMachineGroup] => 1
    [strMachineGroupID] => MC000027
    [strMachineGroupIDUE] => MC000027 
)

Demo on 3v4l.org

If I understood it right, you need to use uksort() function. It allows you to write your own comparator. But what about indexes without month and dates after %monthname%?

The below method works by trying to split the keys on a dash. Then a comparison is made on the second part (index 1) if available, if not a comparison is made with the key.

An example comparison between the keys July-201906_QTY and June-201906_QTY would break down to a comparison between 201906_QTY and 201906_QTY in the uksort.

Numbers will float to the top ordered. The grunt work is done via the spaceship operator.

<?php
$data =
[
    'strMachineGroupID' => MC000027,
    'strMachineGroup' => 1,
    'April-201904_QTY' => 1,
    'February-201902_QTY' => 1,
    'January-201901_QTY' => 1,
    'July-201907_QTY' => 1,
    'June-201906_QTY' => 1,
    'March-201903_QTY' => 1,
    'May-201905_QTY' => 1,
    'strMachineGroupIDUE' => MC000027,
    'April-201904_UE' => 1.00,
    'February-201902_UE' => 1.00,
    'January-201901_UE' => 1.00,
    'July-201907_UE' => 1.00,
    'June-201906_UE' => 1.00,
    'March-201903_UE' => 1.00,
    'May-201905_UE' => 1.00
];

uksort($data, function($a, $b) {
    $parts_a = explode('-', $a);
    $parts_b = explode('-', $b);

    return ($parts_a[1] ?? $a) <=> ($parts_b[1] ?? $b);
});

var_export($data);

Output:

array (
'January-201901_QTY' => 1,
'January-201901_UE' => 1.0,
'February-201902_QTY' => 1,
'February-201902_UE' => 1.0,
'March-201903_QTY' => 1,
'March-201903_UE' => 1.0,
'April-201904_QTY' => 1,
'April-201904_UE' => 1.0,
'May-201905_QTY' => 1,
'May-201905_UE' => 1.0,
'June-201906_QTY' => 1,
'June-201906_UE' => 1.0,
'July-201907_QTY' => 1,
'July-201907_UE' => 1.0,
'strMachineGroup' => 1,
'strMachineGroupID' => 'MC000027',
'strMachineGroupIDUE' => 'MC000027',
)

Here's another option that isn't reliant on anything but the literal month name at the beginning of the string followed by a dash.

uksort($arr, function($a, $b) {
    $months = array_flip(
        ["January", "February", "March", "April", "May", "June",  "July",
         "August", "September", "October", "November", "December"]
    );

    if (preg_match("`^([A-Z][a-z]+)-`", $a, $x) && array_key_exists($x[1], $months)) {
        if (preg_match("`^([A-Z][a-z]+)-`", $b, $y) && array_key_exists($y[1], $months)) {
            if ($months[$x[1]] === $months[$y[1]]) {
                return $a > $b;
            }

            return $months[$x[1]] - $months[$y[1]];
        }

        return -1;
    }

    return $a > $b;
});

Output:

Array
(
    [January-201901_UE] => 1
    [January-201901_QTY] => 1
    [February-201902_QTY] => 1
    [February-201902_UE] => 1
    [March-201903_UE] => 1
    [March-201903_QTY] => 1
    [April-201904_UE] => 1
    [April-201904_QTY] => 1
    [May-201905_UE] => 1
    [May-201905_QTY] => 1
    [June-201906_QTY] => 1
    [June-201906_UE] => 1
    [July-201907_UE] => 1
    [July-201907_QTY] => 1
    [strMachineGroup] => 1
    [strMachineGroupID] => MC000027
    [strMachineGroupIDUE] => MC000027
)

Try it!

asort will sort array by the value. ksrot will sort array by the key (use string sort).If you make the key only has number,you can use ksort to sort it.But you must do something specials for string key strMachineGroup,strMachineGroupID,strMachineGroupIDUE

Array
(
    [strMachineGroupID] => MC000027
    [strMachineGroup] => 1
    [201904_QTY] => 1
    [201902_QTY] => 1
    [201901_QTY] => 1
    [201907_QTY] => 1
    [201906_QTY] => 1
    [201903_QTY] => 1
    [201905_QTY] => 1
    [strMachineGroupIDUE] => MC000027
    [201904_UE] => 1.00
    [201902_UE] => 1.00
    [201901_UE] => 1.00
    [201907_UE] => 1.00
    [201906_UE] => 1.00
    [201903_UE] => 1.00
    [201905_UE] => 1.00
)
Related