Сортировка двумерного массива на основе столбца, содержащего временные диапазоны в формате AM/PM.

У меня есть 2D-массив с именем $props, структура которого выглядит следующим образом:

$props = [
    ['name' => 'Mathmatics', 'time' => '03:01:PM - 04:50:PM'],
    ['name' => 'History', 'time' => '11:30:AM - 01:30:PM'],
    ['name' => 'French', 'time' => '01:31:PM - 03:00:PM'],
];

Мне нужно отсортировать массив по ключу «время», чтобы получить следующий результат:

[
    ['name' => 'History', 'time' => '11:30:AM - 01:30:PM'],
    ['name' => 'French', 'time' => '01:31:PM - 03:00:PM'],
    ['name' => 'Mathmatics', 'time' => '03:01:PM - 04:50:PM'],
];

Я нашел решение с помощью usort, решение выглядит следующим образом:

usort($props, function ($a, $b) {
    return $a["time"] - $b["time"];
});

Однако это не работает, возможно, из-за особого формата моего времени (но мне придется следовать этому конкретному формату времени) и показывает ошибку и ничего не делает с массивом. Ошибка:

Примечание. В C:\xampp..... обнаружено некорректное числовое значение.

$a["time"] - $b["time"] пытается вычесть строку с другой строкой, что по понятным причинам не сработает (и не имеет смысла). Если можете, добавьте время начала в виде отдельного ключа в лучшем формате (например, 1130, 1331, 1501 и т. д.) и используйте его вместо этого. Что-то вроде return $a['sortTime'] <=> $b['sortTime'];
M. Eriksson 21.11.2022 18:41

«Однако это не работает, возможно, из-за особого формата моего времени» — тогда почему бы не настроить данные в этом usort закрытии?

Nico Haase 22.11.2022 11:41
Шлюз в PHP
Шлюз в PHP
API-шлюз (AG) - это сервер, который действует как единая точка входа для набора микросервисов.
Socialite Login With Google Account In Laravel 9
Socialite Login With Google Account In Laravel 9
Этот пост изначально был опубликован на techsolutionstuff.com.
Обновление драйверов Microsoft ODBC (с 17 до 18) для PHP
Обновление драйверов Microsoft ODBC (с 17 до 18) для PHP
Все знают, что PHP v7.4 потерял поддержку, и наши недавние старые приложения должны обновиться до PHP v8.x. ...
Роли и разрешения пользователей без пакета Laravel 9
Роли и разрешения пользователей без пакета Laravel 9
Этот пост изначально был опубликован на techsolutionstuff.com .
Как создать PHP Image с нуля
Как создать PHP Image с нуля
Сегодня мы создадим PHP Image from Scratch для того, чтобы легко развернуть базовые PHP-приложения. Пожалуйста, имейте в виду, что это разработка для...
Как установить LAMP Stack - Security 5/5 на виртуальную машину Azure Linux VM
Как установить LAMP Stack - Security 5/5 на виртуальную машину Azure Linux VM
В предыдущей статье мы завершили установку базы данных, для тех, кто не знает.
1
3
66
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

учитывая формат даты (03:01:PM - 04:50:PM и т. д.), его необходимо сделать способным к сортировке, сохраняя при этом исходное значение.

из вашего вопроса видно, что для сортировки используется только первая часть (03:01:PM). даже если это не так, давайте сохраним его для примера (его можно легко расширить).

учитывая локаль C, преобразование времени позволяет получить строку, которую можно просто отсортировать (двоичный порядок строк):

          03:01:PM
         /   |    \
    (\d\d):(\d\d):(AM|PM)
       \1     \2     \3
              -->   
             \3\1\2
             PM0301

при наличии одного $time в качестве входных данных преобразование можно выполнить с помощью поиска и замены регулярного выражения:

preg_replace(
    '~^(\d+):(\d+):(AM|PM) - .*$~',
    '\3\1\2',
    $time
);
# ~> "PM0301"

Теперь, чтобы отсортировать массив $props, отсортируйте массив всех преобразованных $times и $props:

$times = preg_replace(
    '~^(\d\d):(\d\d):(AM|PM) - .*$~',
    '\3\1\2',
    array_column($props, 'time')
);

array_multisort($times, $props);

Теперь $props сортируется по $times:

[
        [
            'name' => 'History',
            'time' => '11:30:AM - 01:30:PM',
        ],
        [
            'name' => 'French',
            'time' => '01:31:PM - 03:00:PM',
        ],
        [
            'name' => 'Mathematics',
            'time' => '03:01:PM - 04:50:PM',
        ],
];

Пример на 3v4l.org.

Ответ принят как подходящий

В этом решении используется usort со специальной функцией сортировки. Объекты даты создаются с использованием substr и DateTime::createFromFormat. Оператор космического корабля используется для сравнения.

$arr = [
  ['name' => 'Mathmatics', 'time' => '03:01:PM - 04:50:PM'],
  ['name' => 'History', 'time' => '11:30:AM - 01:30:PM'],
  ['name' => 'French', 'time' => '01:31:PM - 03:00:PM'],
];

usort($arr,function($a,$b){
  $dta = DateTime::createFromFormat('h:i:A',substr($a['time'],0,8));
  $dtb = DateTime::createFromFormat('h:i:A',substr($b['time'],0,8));
  return $dta <=> $dtb;
});

print_r($arr);

Попробуйте сами: https://3v4l.org/Fq9U5

Этот вариант сортируется по началу временного интервала. Если требуется только конец, вы можете использовать

DateTime::createFromFormat('h:i:A - h:i:A',$a['time']); //same with $b

Анализ обоих выражений времени в диапазоне с помощью h:i:A - h:i:A приводит к тому, что объект datetime учитывает только время окончания (что может быть не идеальным для всех случаев использования) 3v4l.org/FAFus

mickmackusa 23.11.2022 00:05

@mickmackusa: Да, либо по времени начала, либо по времени окончания. Я понятия не имею, как можно сделать сортировку, которая учитывает время начала и время окончания.

jspit 23.11.2022 09:13

Для подхода без регулярных выражений и с наименьшим количеством повторных вызовов функций используйте array_map() с повторными вызовами createFromFormat() и используйте этот сгенерированный массив сортировки в качестве первого параметра array_multisort() для сортировки входного массива.

Обратите внимание, что + в методе createFromFormat() требует, чтобы все остальные символы игнорировались.

Код: (Демо)

array_multisort(
    array_map(
        fn($row) => DateTime::createFromFormat('h:i:A+', $row['time']),
        $props
    ),
    $props
);

var_export($props);

Знак + в формате является хорошим решением, когда предупреждение в DateTime::getLastErrors() не является проблемой.

jspit 22.11.2022 09:27

@jspit Я думаю, ты знаешь что-то, чего не знаю я. Пожалуйста, объясни.

mickmackusa 22.11.2022 09:36

возвращает "'предупреждения' => массив ( 8 => 'Конечные данные')". Совершенно излишне, если я указываю с помощью «+», что остальные данные следует игнорировать. 3v4l.org/cf9Wb

jspit 22.11.2022 09:55

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