9

我有以下数组:

[
     [
         'schedules' => [
             'monday' => 1,
             'tuesday' => 1,
             'wednesday' => 1,
             'thursday' => 1,
             'friday' => 1,
             'saturday' => 0,
             'sunday' => 1,
         ]
    ]
]

我想旋转这个数组的元素,第一个键是明天。假设今天是星期三,我希望我的数组看起来像这样:

[
     [
         'schedules' => [
             'thursday' => 1,
             'friday' => 1,
             'saturday' => 0,
             'sunday' => 1,
             'monday' => 1,
             'tuesday' => 1,
             'wednesday' => 1,
         ]
    ]
]

我已经有可用的工作日(例如字符串'thursday')。它被传递到我正在使用的函数中。

4

12 回答 12

5

如果将日期转换为数字 0-6,则可以array_shift多次array_push将前几天移动到数组的末尾。

于 2012-07-16T02:24:24.227 回答
3

尝试使用uksort(). 您可以在链接中描述的回调函数中比较日期。

例如:

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

uksort($array, "compare"); 

是它工作的证明

于 2012-07-16T02:25:55.793 回答
2

您可以通过日期函数获取星期几。星期日为 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
});
于 2012-07-16T02:32:16.590 回答
2

你可以这样做来实现这一点

$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
    )
于 2018-07-04T08:02:09.907 回答
1

如果您将uksort与一个简单的函数结合起来,这是一个非常简单的解决方案。

显然需要将日期名称字符串转换为整数,但如果这一天在当前工作日之前,只需将 7 添加到变量中,这将保证数组排序为“之后”,即使星期几意味着否则。

<?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")
?>
于 2012-07-16T03:46:30.530 回答
1

首先,您需要一个正确顺序的列表,您可以通过 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;
}

您可以在演示中看到它的工作原理。

于 2012-07-16T02:26:51.180 回答
1

此答案允许从一周中的哪一天开始,并动态处理如何标记日期。

这只是使用uksort()date()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);
于 2017-04-05T03:22:04.670 回答
0

我写了一个解决方案,它不会将日期转换为日期/时间类型,而是使用闭包和 uksort。本质上,传递给 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.2e-5 秒来对数组进行排序。好奇的人会检查这个答案的第一个版本,以找到一个性能较低的版本,它花费了大约两倍的时间,5.5e-5 秒。

于 2012-07-16T02:40:23.127 回答
0

子数组数据中已经存在循环顺序,因此不需要通过将每个条目相互比较来进行排序。

最直接的解决方案(据我所知)是:

  1. 找到正确的位置将数组分成两部分,然后
  2. 取下第一部分并在第二部分后重新连接。

代码:(演示

$newStart = 'thursday';
foreach ($array as &$entry) {
    $position = array_search(
        $newStart,
        array_keys($entry['schedules'])
    );
    if ($position) {
        $entry['schedules'] += array_splice(
            $entry['schedules'],
            0,
            $position
        );
    }
}
var_export($array);

false如果未找到目标键 ( ) 或已在第一个位置 ( ) ,则该条件确保不执行元素旋转0

array_search()是有效的,因为它在找到第一个匹配项后立即停止迭代。

我不认可任何建议的早期答案:

  • uksort()-- 这具有更大的计算复杂度,更不用说自定义函数体中函数调用的额外开销。
  • 循环——迭代的函数调用不必要地昂贵,并且代表了一种不太优雅/蛮力的技术。具有中断条件且没有迭代函数调用的循环不会那么糟糕。
  • 更改 OP 的输入数据以更好地适应替代解决方案——这是不必要的承认失败。

我的解决方案恰好适合作为实用功能,因为它不依赖于任何与日期相关的数据/逻辑。

于 2021-05-28T13:35:24.393 回答
0

array_slice和的组合array_merge可以解决问题。

'week' => [
   'monday' => 1,
   'tuesday' => 1,
   'wednesday' => 1,
   'thursday' => 1,
   'friday' => 1,
   'saturday' => 0,
   'sunday' => 1,
         ]
// get today's index, like Wednesday will be 3
$day = date('w')

// Get the days until today
$previous = array_slice($week, 0, $day); // ["mon","tue","wed"]

// Get remaining days in week
$coming = array_slice($week, $day); //  ["thu","fri","sat","sun",]

array_merge($coming, $previous);//["thu","fri","sat","sun","mon","tue","wed"]
于 2022-02-14T14:24:51.333 回答
0

试试下面的代码。它将根据当前日期对日期进行排序。

    $days = array("Friday","Thursday","Wednesday","Tuesday");
    $days = array_combine($days,$days);
    
    //loop the days and check the next day
    foreach($days as $k => $dd){
        
        //check next day name & increment current date with +1
        $current_dt = date("Y-m-d",strtotime("next day", strtotime($current_dt)));
        $days_name = date("l", strtotime($current_dt));    
        
        // if day name exists in array, push in seperate array
        if(!empty($days[$days_name])){
            $arrSortedDays[] = $days_name;
        }
    }
    
    //check if currnet day fall today, push it in array to last element.
    if(!empty($days[date("l")])){
        $arrSortedDays[] = date("l");
    } 
于 2020-08-24T13:45:48.140 回答
-1

这对我有用,只是一个简单的循环:

$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'
)
于 2014-05-27T10:30:16.437 回答