Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

PHP multidimensional array sort with column priority

I have the following array:

$data = 
[
    [
        'totals' => ['grand_total' => 729.81, 'lowest_order_date' => '', 'lowest_created_at' => '2022-11-23 15:23:06'],
    ],
    [
        'totals' => ['grand_total' => 746.03, 'lowest_order_date' => '', 'lowest_created_at' => '2022-11-22 19:46:13'],
    ],
    [
        'totals' => ['grand_total' => 729.81, 'lowest_order_date' => '2022-11-22 15:30:22', 'lowest_created_at' => '2022-11-21 14:25:07'],
    ],
];  

And I’m using the following code to sort it:

usort($data, function ($a, $b)
{
    return
        ($a['totals']['grand_total'] <=> $b['totals']['grand_total']) + 
        ($a['totals']['lowest_order_date'] <=> $b['totals']['lowest_order_date']) +
        ($a['totals']['lowest_created_at'] <=> $b['totals']['lowest_created_at']);
});

I was expecting this function to sort the content by the following priority:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

  1. Grand total <– The main priority ASC
  2. Lowest order date <– If grand total equal, check this
  3. Lowest created at <– If grand total equal, check this

However, the output puts the 746.03 as first result:

$data = 
[
    [
        'totals' => ['grand_total' => 746.03, 'lowest_order_date' => '', 'lowest_created_at' => '2022-11-22 19:46:13'],
    ],
    [
        'totals' => ['grand_total' => 729.81, 'lowest_order_date' => '', 'lowest_created_at' => '2022-11-23 15:23:06'],
    ],
    [
        'totals' => ['grand_total' => 729.81, 'lowest_order_date' => '2022-11-08 15:30:22', 'lowest_created_at' => '2022-11-21 14:25:07'],
    ],
];

Expected output:

$data = 
[
    [
        'totals' => ['grand_total' => 729.81, 'lowest_order_date' => '', 'lowest_created_at' => '2022-11-23 15:23:06'],
    ],
    [
        'totals' => ['grand_total' => 729.81, 'lowest_order_date' => '2022-11-22 15:30:22', 'lowest_created_at' => '2022-11-21 14:25:07'],
    ],
    [
        'totals' => ['grand_total' => 746.03, 'lowest_order_date' => '', 'lowest_created_at' => '2022-11-22 19:46:13'],
    ],  
];

By looking at the problem, it seems to me logical that I first need to sort only by grand_total and then perform sort on lowest_order_date & lowest_created_at if the grand_total is equal. Is there an easy way to do it by using the sort functions?

>Solution :

Adding together the results from <=> is probably not what you want, as it could return a -1 and a 1 and those negate to 0. Same goes for the return from strcmp() and friends.

usort($data, function ($a, $b)
{
    // First priority
    if (($result = ($a['totals']['grand_total'] <=> $b['totals']['grand_total'])) !== 0) {
        return $result;
    }
    // Second priority
    if (($result = ($a['totals']['lowest_order_date'] <=> $b['totals']['lowest_order_date'])) !== 0) {
        return $result;
    }
    // Lowest priority
    return $a['totals']['lowest_created_at'] <=> $b['totals']['lowest_created_at']);
});

DRYing up the code:

usort($data, function ($a, $b)
{
    // Keys in 'totals', highest-to-lowest sort priority
    $sort_priority = [
        'grand_total',
        'lowest_order_date',
        'lowest_created_at',
    ];
    foreach ($sort_priority as $sort_key) {
        if (($result = ($a['totals'][$sort_key] <=> $b['totals'][$sort_key])) !== 0) {
            return $result;
        }
    }
    // Compared all fields, they're a tie for sort order
    return 0;
});
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading