通过创建由连续月份组成的连字符表达式来减少月份名称数组。

4

我有一个类似的数组:

Array
(
    [0] => Jan
    [1] => Feb
    [2] => Mar
    [3] => Apr
    [4] => May
    [5] => Jun
    [6] => Sep
    [7] => Oct
    [8] => Dec
)

我需要将它转换为

Array
(
    [0] => "Jan - Jun"
    [1] => "Sep - Oct"
    [2] => "Dec"
)

月份将始终按顺序排列,但由于数组是动态的,我想不出比使用date_parse将每个月转换为数字,然后与其周围的月份组合更好有效的方法!但是我真的很困惑如何做到这一点,有什么想法吗?

2
你能详细说明一下问题吗?为什么你的例子中范围不均匀?你在形成范围时有任何规则吗? - Arthur Nicoll
...还有可能发布构建数组的代码。 - user20232359723568423357842364
你从哪里获取范围参数?一对日期吗? - Tony Hopkinson
1
如果不将月份转换为数字,您需要一些东西来告诉您连续的月份是什么样子的,因此您的解决方案需要一个包含所有月份的数组,然后循环遍历您的动态数组并与该列表进行比较。尝试一下并展示代码以获得反馈。 - lurker
问题是,这是一个更大系统的一部分,用户将选择多个日期范围,我必须列出所有在这些范围之外的月份...所以列表将完全是随机的。 - Bluemagica
显示剩余2条评论
3个回答

2
像这样怎么样:
function findConsecutiveMonths(array $input) {
    // Utility list of all months
    static $months = array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
                           'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec');

    $chunks = array();

    for ($i = 0; $i < 12; $i++) {
        // Wait until the $i-th month is contained in the array
        if (!in_array($months[$i], $input)) {
            continue;
        }

        // Find first consecutive month that is NOT contained in the array
        for ($j = $i + 1; $j < 12; $j++) {
            if (!in_array($months[$j], $input)) {
                break;
            }
        }

        // Chunk is from month $i to month $j - 1
        $chunks[] = ($i == $j - 1) ? $months[$i] : $months[$i] .' - '. $months[$j - 1];

        // We know that month $j is not contained in the array so we can set $i
        // to $j - the search for the next chunk is then continued with month
        // $j + 1 because $i is incremented after the following line
        $i = $j;
    }

    return $chunks;
}

Demo: http://codepad.viper-7.com/UfaNfH


这比我的版本快两倍。 - Gerald Schneider

0

这应该可以:

function combine_months($months) {
    $all_months = array("Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec");
    $target = array();
    $start = null;
    for ($i = 0; $i<12; $i++) {
        if (!in_array($all_months[$i], $months) && $start != null) {
            if ($start == null) {
                $target[] = $all_months[$i-1];
            }
            else {
                $target[] = sprintf("%s - %s", $start, $all_months[$i-1]);
            }
            $start = null;
        }
        elseif ($start == null) {
            $start = $all_months[$i];
        }
    }
    if ($start != null) {
        $target[] = $start;
    }
    return $target;
}

$test = combine_months(array("Jan","Feb","Mar","Apr","May","Jun","Sep","Oct","Dec"));
var_dump($test);

它迭代所有可用的月份,记住第一个公共月份,在缺少月份时添加到目标数组中。


0
作为我的这个答案的改编,使用查找数组和引用将连续的月份名称推入正确的元素中--使用strtok()和连接确保范围的结尾始终正确更新。
此片段的性能表现良好,因为它只使用一个循环,并且没有in_array()调用(PHP中最慢的搜索数组之一)。
代码:(演示
$lookup = array_flip(['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']);

$months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Sep', 'Oct', 'Dec'];
$result = [];
foreach ($months as $month) {
    if (isset($ref) && $lookup[$month] === $lookup[$last] + 1) {
        $ref = strtok($ref, "-") . "-$month";
    } else {
        unset($ref);
        $ref = $month;
        $result[] = &$ref;
    }
    $last = $month;
}
var_export($result);

或者换一种方式,利用 $i 而不是 $last,因为输入数组是有索引的。(演示)
$result = [];
foreach ($months as $i => $month) {
    if ($i && $lookup[$month] === $lookup[$months[$i - 1]] + 1) {
        $ref = strtok($ref, "-") . "-$month";
    } else {
        unset($ref);
        $ref = $month;
        $result[] = &$ref;
    }
}
var_export($result);

如果您的输入数组需要容纳循环引用,请使用模运算符与12(一年中的月份数)结合,以确保1月“回溯”到12月。(演示
if (isset($ref) && $lookup[$month] === ($lookup[$last] + 1) % 12) {

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接