Sorting 3 dimensional array at 2nd level based on 3rd level values

假装没事ソ 提交于 2019-12-12 03:36:46

问题


I am using the Google Calendar API to pull data from multiple calendars. I am creating an array so I can format the display of the data. I am having trouble sorting the data so events will appear in the proper order.

My primary sort is on datetime ASC. If the two datetimes are equal I want to sort on alldayflag DESC. I only want it sorted within each date.

Here is a sample of my data:

Array 
( 
[2016-01-29] => Array 
    ( 
        [0] => Array 
            ( 
                [date] => January 29 
                [time] => 8:30 am 
                [datetime] => 2016-01-29T08:30:00-06:00 
                [alldayflag] => 0 
            ) 
        [1] => Array 
            ( 
                [date] => January 29 
                [time] => 12:00 am 
                [datetime] => 2016-01-29T00:00:00-06:00 
                [alldayflag] => 1 
            ) 
        [2] => Array 
            ( 
                [date] => January 29 
                [time] => 2:00 pm 
                [datetime] => 2016-01-29T14:00:00-06:00 
                [alldayflag] => 0 
            ) 
        [3] => Array 
            ( 
                [date] => January 29 
                [time] => 10:00 am 
                [datetime] => 2016-01-29T10:00:00-06:00 
                [alldayflag] => 0 
            ) 
        [4] => Array 
            ( 
                [date] => January 29 
                [time] => 12:00 pm 
                [datetime] => 2016-01-29T12:00:00-06:00 
                [alldayflag] => 0 
            ) 
    ) 
[2016-01-30] => Array 
    ( 
        [0] => Array 
            ( 
                [date] => January 30 
                [time] => 4:00 pm 
                [datetime] => 2016-01-30T16:00:00-06:00 
                [alldayflag] => 0 
            ) 
        [1] => Array 
            ( 
                [date] => January 30 
                [time] => 5:00 pm 
                [datetime] => 2016-01-30T17:00:00-06:00 
                [alldayflag] => 0 
            ) 
        [2] => Array 
            ( 
                [date] => January 30 
                [time] => 11:00 am 
                [datetime] => 2016-01-30T11:00:00-06:00 
                [alldayflag] => 0 
            ) 
    ) 
)

I have tried using array_multisort(). I get the proper sorting results however I also get the error message:

Warning: array_multisort(): Array sizes are inconsistent in sort-array.php on line XXX

$getBeginDate = '2016-01-29';
$getEndDate = '2016-01-31';

$getCurrentDate = $getBeginDate;

while(strtotime($getCurrentDate) < strtotime($getEndDate)) {

    foreach ($list[$getCurrentDate] as $key => $row){
         $datetime[$key] = $row['datetime'];
         $alldayflag[$key] = $row['alldayflag'];
    }

    array_multisort($datetime, SORT_ASC, $alldayflag, SORT_DESC, $list[$getCurrentDate]);

    $getCurrentDate = date('Y-m-d', strtotime($getCurrentDate . " +1 day"));

}

I have also tried uasort(). It doesn't sort properly at all.

uasort($list, 'sortCriteria');

function sortCriteria($array, $key) {
    if(strtotime($a['datetime']) == strtotime($b['datetime'])) {
        if($a['allday'] < $b['allday']) {
            return -1;
        } else {
            return 0;
        }
    }

    return (strtotime($a['datetime']) < strtotime($b['datetime'])) ? -1 : 1;

}

Any help is greatly appreciated.


回答1:


array_multisort is definitely the way that you want to go. I have an untested answer for you, so may I be smited by the wrath of the community if it's an incorrect guess, but it looks like you're running into a closure issue, or rather the lack thereof. This should fix your issue:

...
while(strtotime($getCurrentDate) < strtotime($getEndDate)) {

$datetime = [];
$alldayflag = [];
foreach ($list[$getCurrentDate] as $key => $row){
...

My guess from the error you mentioned is that if you dumped $datetime before the multisort it would have 5 items in it the first time and 5 items in it the second time.

first_dump => '29th', '29th', '29th', '29th', '29th'
second_dump => '30th', '30th', '30th', '29th', '29th'

Or something similar to this. What's happening is $datetime is persisting through the first round of the while loop into the second time. Which is bombing out your multisort the second time because there are only 3 items and not 5.

I hope that makes sense.




回答2:


A possible solution could be to use usort. You can then use a DateTime to compare the 'datetime'. Then if two datetimes are equal, you can compare the 'alldayflag'.

For example:

function sortCriteria($a, $b)
{
    $aDateTime = new DateTime($a['datetime']);
    $bDateTime = new DateTime($b['datetime']);

    if ($aDateTime == $bDateTime) {
        return ($a['alldayflag'] > $b['alldayflag']) ? -1 : 1;
    }

    return ($aDateTime < $bDateTime) ? -1 : 1;
}

$getBeginDate = '2016-01-29';
$getEndDate = '2016-01-31';
$getCurrentDate = $getBeginDate;

while(strtotime($getCurrentDate) < strtotime($getEndDate)) {
    usort($list[$getCurrentDate], 'sortCriteria');
    $getCurrentDate = date('Y-m-d', strtotime($getCurrentDate . " +1 day"));
}

Demo



来源:https://stackoverflow.com/questions/35097681/sorting-3-dimensional-array-at-2nd-level-based-on-3rd-level-values

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!