0

So I have a 2D array that looks a bit like this:

[0] => Array(
    [date] => 23-01-2017
    [name] => bbb
    [othertext] => text2
)
[1] => Array(
    [date] => 23-01-2017
    [name] => aaa
    [othertext] => text3
)
[2] => Array(
    [date] => 24-01-2017
    [name] => aaa
    [othertext] => text1
)

NOTE: This question is not tagged as MySQL, the database used is MongoDB with the sort type of 'date' => 'asc'.

Currently this is returned from my database sorted by date, but does not take into account the name property. I'd like to now sort this by date, and for entries with the same date to then sort by name.

My current approach is to run an array_multisort on the data:

array_multisort(
    $array['date'], SORT_STRING,
    $array['name'], SORT_STRING,
    $arrayCopy //<--This copy of the array has the full datetime object
);

But this then sorts the date as a string, so in certain scenarios it sorts it incorrectly; e.g. 1st March would go before the 2nd Feb. If putting the month first then again it sorts incorrectly when Dec/Jan dates are sorted.

What's the correct approach to this? I've seen mention of usort(), but I'm unsure how to implement it in this use case. Does array_multisort have functionality for dates?

3 Answers3

0

In your database query:

SELECT * from `your_table_name` order by date asc, name asc;

Maybe this in mongodb:

 $cursor->sort(array('date' => 1, 'name' => 1));

See: http://php.net/manual/en/mongocursor.sort.php

No need to do it in php afterwards.

Tschallacka
  • 27,901
  • 14
  • 88
  • 133
0

I would strongly suggest doing this via the database.

But if you must use usort or are trying to understand how it works:

$arr = [
    [
        'date' => '23-01-2017',
        'name' => 'bbb',
    ],
    [
        'date' => '23-01-2017',
        'name' => 'aaa',
    ],
    [
        'date' => '24-01-2017',
        'name' => 'aaa',
    ],
];

function cmp($a, $b)
{
    $aDate = DateTime::createFromFormat('d-m-Y', $a['date']);
    $bDate = DateTime::createFromFormat('d-m-Y', $b['date']);


    if ($aDate == $bDate) {
        if ($a['name'] == $b['name']) {
            return 0;
        }
        return ($a['name'] < $b['name']) ? -1 : 1;
    }
    return ($aDate < $bDate) ? -1 : 1;
}

usort($arr, "cmp");

print_r($arr);

http://php.net/manual/en/function.usort.php

Outputs:

[0] => Array
    (
        [date] => 23-01-2017
        [name] => aaa
    )

[1] => Array
    (
        [date] => 23-01-2017
        [name] => bbb
    )

[2] => Array
    (
        [date] => 24-01-2017
        [name] => aaa
    )
lookbadgers
  • 988
  • 9
  • 31
0

With usort-function you could do:

$foo = array(
  0 => array(
    "date" => "23-01-2017",
    "name" => "bbb",
    "othertext" => "text2"
  ),
  1 => array(
    "date" => "23-01-2017",
    "name" => "aaa",
    "othertext" => "text3"
  ),
  2 => array(
    "date" => "24-01-2017",
    "name" => "aaa",
    "othertext" => "text1"
  )
);

usort($foo, function($a, $b)
{
  return $a["date"] === $b["date"] ? strcmp($a["name"], $b["name"]) : strcmp(strtotime($a["date"]), strtotime($b["date"]));
});

var_dump($foo);
Corrodian
  • 75
  • 1
  • 12