对工作日名称数组进行排序

时间:2012-07-16 02:15:19

标签: php arrays algorithm sorting

我有以下数组:

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

         )
 )

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

有关实现此类排序的任何建议吗?谢谢!

11 个答案:

答案 0 :(得分:5)

如果您将当天转换为0-6,那么您可以多次array_shiftarray_push将前几天移动到数组的末尾。

答案 1 :(得分:3)

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

例如:

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

uksort($array, "compare"); 

这是proof of it working

答案 2 :(得分:3)

您可以通过date功能获取星期几。星期日是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 :(得分: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
    )

答案 4 :(得分: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;
}

您可以在the demo中看到它。

答案 5 :(得分:1)

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

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

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

答案 6 :(得分: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秒。

答案 7 :(得分:0)

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

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

答案 8 :(得分:0)

此答案允许从哪一天开始,并动态处理天数的标记。

这只是使用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);

答案 9 :(得分: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");
    } 

答案 10 :(得分:0)

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

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

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

代码:(Demo)

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

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