Сортировка трехмерного массива на 2-м уровне по значениям 3-го уровня

Я использую Google Calendar API для извлечения данных из нескольких календарей. Я создаю массив, чтобы я мог отформатировать отображение данных. У меня проблемы с сортировкой данных, чтобы события отображались в правильном порядке.

Мой основной вид включен datetime ASC. Если два даты совпадают, я хочу отсортировать alldayflag DESC. Я только хочу, чтобы это сортировалось в пределах каждой даты.

Вот образец моих данных:

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 
            ) 
    ) 
)

Я пытался использовать array_multisort(), Я получаю правильные результаты сортировки, однако я также получаю сообщение об ошибке:

Предупреждение: array_multisort(): размеры массива несовместимы в файле sort-array.php в строке 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"));

}

Я также пытался uasort(), Это не сортирует должным образом вообще.

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;

}

Любая помощь с благодарностью.

2 ответа

Решение

array_multisort это определенно путь, по которому вы хотите идти. У меня есть непроверенный ответ для вас, так что, может быть, меня поразит гнев сообщества, если это неверное предположение, но похоже, что вы столкнулись с проблемой закрытия или, скорее, с ее отсутствием. Это должно исправить вашу проблему:

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

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

Мое предположение из ошибки, которую вы упомянули, заключается в том, что если вы сбросили $datetime перед мультисортикой в ​​нем будет 5 элементов в первый раз и 5 элементов во второй раз.

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

Или что-то похожее на это. Происходит следующее: $datetime сохраняется во время первого раунда цикла while во второй раз. Который бомбит Ваш мультисорт во второй раз, потому что есть только 3 пункта, а не 5.

Я надеюсь, что в этом есть смысл.

Возможным решением может быть использование usort. Затем вы можете использовать DateTime для сравнения "datetime". Тогда, если два datetime равны, вы можете сравнить 'alldayflag'.

Например:

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"));
}

демонстрация

Другие вопросы по тегам