Сортировка массива названий дней недели


У меня есть следующий массив:

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

         )
 )

У меня уже есть доступный день недели (например, строка "четверг"). Он передается в функцию, с которой я работаю.

Есть какие-либо предложения по достижению такого типа сортировки? Спасибо!

Author: kwikness, 2012-07-16

9 answers

Если вы преобразуете день в число 0-6, вы можете array_shift и array_push столько раз перемещать предыдущие дни в конец массива.

 5
Author: Adam Bergmark, 2012-07-16 02:24:24

Вы можете узнать день недели с помощью функции дата. Воскресенье - 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
});
 3
Author: Vulcan, 2012-07-16 02:41:21

Попробуйте использовать uksort(). Вы можете сравнить даты в функции обратного вызова, описанной по ссылке.

Например:

function compare($a, $b) { 
  date(strtotime($a)) - date(strtotime($b)); 
}

uksort($array, "compare"); 

Вот доказательство того, что это работает

 3
Author: Marty Cortez, 2012-07-16 02:46:47

Сначала вам нужен список в правильном порядке, который вы можете получить с помощью класса 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;
}

Вы можете увидеть, как это работает в демо-версии.

 1
Author: nickb, 2012-07-16 02:33:35

Если вы объедините 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")
?>
 1
Author: Fluffeh, 2012-07-16 03:54:48

Вы можете сделать вот так, чтобы достичь этого

$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
    )
 1
Author: ajuchacko91, 2018-07-04 08:02:09

Я написал решение, которое не приводит дни к типу даты/времени, а вместо этого использует закрытие и уксорт. По сути, каждый ключ, переданный в 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 секунд.

 0
Author: Chris Trahey, 2012-07-16 03:54:55

Это работает для меня, просто простой цикл:

$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'
)
 0
Author: sharif9876, 2014-05-27 10:36:57

Этот ответ позволяет выбрать, с какого дня недели начинать, и динамически обрабатывает, как помечаются дни.

Это просто улучшенное решение с использованием 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);
 0
Author: EkoJR, 2017-05-14 08:48:22