Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.4k views
in Technique[技术] by (71.8m points)

php - sort multidimensional array by date

I have this array:-

array (size=8)
  0 => 
    array (size=2)
      'date' => string '17/05/2016 00:00:00' (length=19)
      'reason' => string 'DNA' (length=3)
  1 => 
    array (size=2)
      'date' => string '10/05/2016 00:00:00' (length=19)
      'reason' => string 'UTA' (length=3)
  2 => 
    array (size=2)
      'date' => string '03/05/2016 00:00:00' (length=19)
      'reason' => string 'DNA' (length=3)
  3 => 
    array (size=2)
      'date' => string '26/04/2016 00:00:00' (length=19)
      'reason' => string 'true' (length=4)
  4 => 
    array (size=2)
      'date' => string '31/05/2016 00:00:00' (length=19)
      'reason' => string 'true' (length=4)
  5 => 
    array (size=2)
      'date' => string '24/05/2016 00:00:00' (length=19)
      'reason' => string 'true' (length=4)
  6 => 
    array (size=2)
      'date' => string '07/06/2016 00:00:00' (length=19)
      'reason' => string 'true' (length=4)
  7 => 
    array (size=2)
      'date' => string '14/06/2016 00:00:00' (length=19)
      'reason' => string 'true' (length=4)

I want to sort it by 'date'

I tried both of the following methods, but the result ( below )is not sorted correctly.

usort($course, function($a, $b) {
    return $a['date'] - $b['date'];
});

_______________________________
function date_compare($a, $b)
{
    $t1 = strtotime($a['date']);
    $t2 = strtotime($b['date']);
    return $t1 - $t2;
}
usort($course, 'date_compare');

This is the "sorted" array

array (size=8)
  0 => 
    array (size=2)
      'date' => string '24/05/2016 00:00:00' (length=19)
      'reason' => string 'true' (length=4)
  1 => 
    array (size=2)
      'date' => string '14/06/2016 00:00:00' (length=19)
      'reason' => string 'true' (length=4)
  2 => 
    array (size=2)
      'date' => string '31/05/2016 00:00:00' (length=19)
      'reason' => string 'true' (length=4)
  3 => 
    array (size=2)
      'date' => string '26/04/2016 00:00:00' (length=19)
      'reason' => string 'true' (length=4)
  4 => 
    array (size=2)
      'date' => string '17/05/2016 00:00:00' (length=19)
      'reason' => string 'DNA' (length=3)
  5 => 
    array (size=2)
      'date' => string '03/05/2016 00:00:00' (length=19)
      'reason' => string 'DNA' (length=3)
  6 => 
    array (size=2)
      'date' => string '07/06/2016 00:00:00' (length=19)
      'reason' => string 'true' (length=4)
  7 => 
    array (size=2)
      'date' => string '10/05/2016 00:00:00' (length=19)
      'reason' => string 'UTA' (length=3)
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You need to modify the datetime strings in your $course array in order to make them comparable in the manner that you want.

One (flexible) way to do this is to create DateTime() objects from your datetime strings and compare those.

A quick note about datetimes: standard US format m/d/Y uses forward slashes, and standard European format d-m-Y uses hyphens. Your datetime strings are a mixture of both, using US-style forward slashes with European day/month/year ordering.

Therefore you'll have to take an additional step to parse each datetime string into a valid DateTime() object before comparing.

Static method DateTime::createFromFormat() can help in this regard. For example, given an array called $course:

$course = [
    [
        'date' => '17/05/2016 00:00:00',
        'reason' => 'DNA',
    ],
    [
        'date'   => '10/05/2016 00:00:00',
        'reason' => 'UTA',
    ],
    [
        'date'   => '03/05/2016 00:00:00',
        'reason' => 'DNA',
    ],
    [
        'date'   => '26/04/2016 00:00:00',
        'reason' => 'true',
    ],
    [
        'date'   => '31/05/2016 00:00:00',
        'reason' => 'true',
    ],
    [
        'date'   => '24/05/2016 00:00:00',
        'reason' => 'true',
    ],
    [
        'date'   => '07/06/2016 00:00:00',
        'reason' => 'true',
    ],
    [
        'date'   => '14/06/2016 00:00:00',
        'reason' => 'true',
    ],
];

You can then apply a callback with usort() which converts the date value of each comparison object into a valid DateTime() objects before comparing them:

usort($course, function ($a, $b) {
    $dateA = DateTime::createFromFormat('d/m/Y H:i:s', $a['date']);
    $dateB = DateTime::createFromFormat('d/m/Y H:i:s', $b['date']);
    // ascending ordering, use `<=` for descending
    return $dateA >= $dateB;
});

print_r($course);

This yields:

Array
(
    [0] => Array
        (
            [date] => 26/04/2016 00:00:00
            [reason] => true
        )

    [1] => Array
        (
            [date] => 03/05/2016 00:00:00
            [reason] => DNA
        )

    [2] => Array
        (
            [date] => 10/05/2016 00:00:00
            [reason] => UTA
        )

    [3] => Array
        (
            [date] => 17/05/2016 00:00:00
            [reason] => DNA
        )

    [4] => Array
        (
            [date] => 24/05/2016 00:00:00
            [reason] => true
        )

    [5] => Array
        (
            [date] => 31/05/2016 00:00:00
            [reason] => true
        )

    [6] => Array
        (
            [date] => 07/06/2016 00:00:00
            [reason] => true
        )

    [7] => Array
        (
            [date] => 14/06/2016 00:00:00
            [reason] => true
        )

)

If your course array is very large, then there may be some overhead in creating DateTime objects on the fly like the example above. YMMV. In this case, I'd consider mapping over the array first and create DateTime objects for each entry, and then apply usort().

Note that, with a standard format datetime string, such as European d-m/Y H:i:s, US m/d/Y H:i:s or IS08601 Y-m-d H:i:s, you can simply pass the datetime string as the first value into the DateTime constructor instead; e.g:

$dt = new DateTime($someStandardFormatDateTimeString);

Apologies about the errant close vote earlier. I've removed that now.

Hope this helps :)


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

1.4m articles

1.4m replys

5 comments

57.0k users

...