Сортировка массива названий дней недели
У меня есть следующий массив:
(
[0] => Array
(
[schedules] => Array
(
[monday] => 1
[tuesday] => 1
[wednesday] => 1
[thursday] => 1
[friday] => 1
[saturday] => 0
[sunday] => 1
)
)
)
Я хотел бы отсортировать элементы этого массива, чтобы первый ключ был завтрашним днем. Допустим, сегодня была среда. Я бы хотел, чтобы мой массив выглядел так:
(
[0] => Array
(
[schedules] => Array
(
[thursday] => 1
[friday] => 1
[saturday] => 0
[sunday] => 1
[monday] => 1
[tuesday] => 1
[wednesday] => 1
)
)
)
У меня уже есть доступный день недели (например, строка "четверг"). Он передается в функцию, с которой я работаю.
Есть какие-либо предложения по достижению такого типа сортировки? Спасибо!
9 answers
Если вы преобразуете день в число 0-6, вы можете array_shift
и array_push
столько раз перемещать предыдущие дни в конец массива.
Вы можете узнать день недели с помощью функции дата. Воскресенье - 0, понедельник - 1 и так далее.
$weekday = date("w");
Затем я предлагаю использовать функцию uksort для сортировки массива относительно его ключей, которая использует функцию обратного вызова в качестве ориентира для сортировки.
uksort($schedules, function ($a, $b) use ($weekday) {
// convert each day to a number 0-6 and compare to $weekday
});
Попробуйте использовать uksort()
. Вы можете сравнить даты в функции обратного вызова, описанной по ссылке.
Например:
function compare($a, $b) {
date(strtotime($a)) - date(strtotime($b));
}
uksort($array, "compare");
Сначала вам нужен список в правильном порядке, который вы можете получить с помощью класса DateTime. Затем, когда вы перебираете старый массив, используйте правильный порядок в качестве ключа для сортировки массива, например:
function sort_by_weekday( $input_array) {
$now = new DateTime( "tomorrow", new DateTimeZone('America/New_York'));
$interval = new DateInterval( 'P1D'); // 1 Day interval
$period = new DatePeriod( $now, $interval, 7); // 7 Days
$sorted_array = array();
foreach( $period as $day) {
$weekday = strtolower( $day->format( 'l'));
foreach( $input_array as $key => $value) {
$sorted_array[ $key ][ $weekday ] = $value[ $weekday ];
}
}
return $sorted_array;
}
Вы можете увидеть, как это работает в демо-версии.
Если вы объедините uksort с простой функцией, это на удивление простое решение.
Очевидно, что необходимо преобразовать строки имени дня в ints, но если день предшествует текущему дню недели, просто добавьте семь в переменную, это гарантирует, что массив будет отсортирован как "после", даже если день недели подразумевает иное.
<?php
$a='sunday'; // Example Input
$b='saturday'; // Example Input
function funnyDateCompare($a, $b)
{
$a=date('w',strtotime($a));
$b=date('w',strtotime($b));
if($a<=date('w'))
{
$a+=7;
// First value is less than or equal to today.
// Adding 7 to the answer.
}
return ($a - $b);
}
uksort($array, "funnyDateCompare")
?>
Вы можете сделать вот так, чтобы достичь этого
$week = [
'sunday',
'monday',
'tuesday',
'wednesday',
'thursday',
'friday',
'saturday',
];
$day = date('w'); // weekday as integer(3 for Wednesday)
for ($i=0; $i <= $day ; $i++) {
array_push($week, array_shift($week));
}
$result = $week;
Результат (если сегодня среда):
Array
(
[0] => thursday
[1] => friday
[2] => saturday
[3] => sunday
[4] => monday
[5] => tuesday
[6] => wednesday
)
Я написал решение, которое не приводит дни к типу даты/времени, а вместо этого использует закрытие и уксорт. По сути, каждый ключ, переданный в uksort, сравнивается с позицией ключа "завтра", и если он "до" завтра, он "продвигается" в будущее (+= 7
), затем используется простой результат сравнения.
Отредактировано для повышения производительности:
Правки, мотивированные комментарием @nickb (спасибо!)
<?php
function sortedWithNext($days, $tomorrow) {
$index_dictionary = array_combine(array_keys($days), range(0,6));
$index_of_tomorrow = $index_dictionary[$tomorrow];
$compare_function = function($k1, $k2) use ($index_dictionary, $index_of_tomorrow) {
$index_of_k1 = $index_dictionary[$k1];
$index_of_k2 = $index_dictionary[$k2];
if($index_of_k1 < $index_of_tomorrow)
$index_of_k1 += 7;
if($index_of_k2 < $index_of_tomorrow)
$index_of_k2 += 7;
return $index_of_k1 - $index_of_k2;
};
uksort($days, $compare_function);
return $days;
}
$daysPool = array(
'monday'=>1,
'tuesday'=>1,
'wednesday'=>1,
'thursday'=>1,
'friday'=>0,
'saturday'=>1,
'sunday'=>1,
);
$tomorrow = 'thursday';
$sortedDays = sortedWithNext($daysPool, $tomorrow);
var_dump($sortedDays);
Примечания к производительности
Я протестировал с использованием 100 000 итерации, этот метод тратит примерно 2,2 e-5 секунд на сортировку массива. Любопытные проверят первую версию этого ответа, чтобы найти менее производительную версию, которая заняла примерно вдвое больше времени, 5,5 e-5 секунд.
Это работает для меня, просто простой цикл:
$array = array();
$month = date('m');
$day = date('d');
$year = date('Y');
for($i=1; $i<=7; $i++){
$array[] = date('l',mktime(0,0,0,$month,($day+$i),$year));
}
Выходной массив выглядит следующим образом: (Если сегодня вторник)
array(
(int) 0 => 'Wednesday',
(int) 1 => 'Thursday',
(int) 2 => 'Friday',
(int) 3 => 'Saturday',
(int) 4 => 'Sunday',
(int) 5 => 'Monday',
(int) 6 => 'Tuesday'
)
Этот ответ позволяет выбрать, с какого дня недели начинать, и динамически обрабатывает, как помечаются дни.
Это просто улучшенное решение с использованием uksort(), дата() и strtotime().
function sort_days( $term1, $term2 ) {
$weekdays = array( 'sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat' );
foreach ( $weekdays as $key => $value ) {
$weekdays[ $key ] = date( 'N', strtotime( $value ) );
}
$term1_time = date( 'N', strtotime( strtolower( $term1 ) ) );
$term2_time = date( 'N', strtotime( strtolower( $term2 ) ) );
return array_search( $term1_time, $weekdays ) - array_search( $term2_time, $weekdays );
}
Сортировка ключей с помощью uksort()
$uk_days = array(
'thursday' => 1,
'monday' => 1,
'saturday' => 1,
'wednesday' => 1,
'sunday' => 1,
'friday' => 1,
'tuesday' => 1,
);
uksort($uk_days, "sort_days");
var_dump($uk_days);
Сортировка ключей с помощью usort()
$u_days = array(
'thursday',
'monday',
'saturday',
'wednesday',
'sunday',
'friday',
'tuesday',
);
usort($u_days, "sort_days");
var_dump($u_days);