按月排序,使它们按顺序排列

时间:2012-07-20 13:09:44

标签: php arrays

我有一个数月(数字,1-12)的数组,我想要排序,这将是最大的连续序列。一个例子:

array(1,2,3)

很简单,那就是Jan-Mar,不需要排序

array(1,2,11,12)

这可能是11月到2月的一个连续序列,所以它应该像11,12,1,2

那样排序

array(1,4,5,11,12)

这应该是4月至5月,11月至1月,所以应该分成两部分:4,5和11,12,1

任何想法如何做到这一点?

5 个答案:

答案 0 :(得分:2)

一旦你弄清楚如何表达12可以回滚到1这一事实,这很容易做到。

这是我的解决方案。它自然地对传入的数组进行排序,然后创建一个如下所示的$months数组:

$months = 1 2 3 4 5 6 7 8 9 10 11 12 1 2 3 4 5 6 7 8 9 10 11 12 

从该数组中,我遍历输入数组,将零置于未设置月份值的位置。 因此,如果输入数组为array( 1, 2, 11, 12),则$inputs数组将变为:

$inputs = 1 2 0 0 0 0 0 0 0 0  11 12 1 2 0 0 0 0 0 0 0 0  11 12

从这里算起来很简单:在$inputs数组上循环,找到不是0的最长序列。这将生成所有可能的连续序列。

function sort_months( $array)
{
    natsort( $array);

    $keys = array_flip( $array);
    $inputs = array();
    $months = array_merge( range( 1, 12), range( 1, 12));

    foreach( $months as $m) {
        $inputs[] = (isset( $keys[$m])) ? $m : 0;
    }

    $sequences = array();

    for( $i = 0, $ii = count( $inputs); $i < $ii; $i++) {
        if( $inputs[$i] != 0) {
            $sequence = array( $inputs[$i]);
            for( $k = $i + 1, $kk = $ii + 1; $k < $kk;  $sequence[] = $inputs[$k], $k++) {
                if( !isset( $inputs[$k]) || $inputs[$k] == 0) {
                    break;
                }
            }
            $sequences[] = $sequence;
        }
    }

    return $sequences;
}

输入array( 12, 11, 1, 2),此will output

array(8) {
  [0]=>
  array(2) {
    [0]=>
    int(1)
    [1]=>
    int(2)
  }
  [1]=>
  array(1) {
    [0]=>
    int(2)
  }
  [2]=>
  array(4) {
    [0]=>
    int(11)
    [1]=>
    int(12)
    [2]=>
    int(1)
    [3]=>
    int(2)
  }
  [3]=>
  array(3) {
    [0]=>
    int(12)
    [1]=>
    int(1)
    [2]=>
    int(2)
  }
  [4]=>
  array(2) {
    [0]=>
    int(1)
    [1]=>
    int(2)
  }
  [5]=>
  array(1) {
    [0]=>
    int(2)
  }
  [6]=>
  array(2) {
    [0]=>
    int(11)
    [1]=>
    int(12)
  }
  [7]=>
  array(1) {
    [0]=>
    int(12)
  }
}

您可以看到最长的连续序列实际上存在于数组中(以及所有其他可能的序列):

[2]=>
  array(4) {
    [0]=>
    int(11)
    [1]=>
    int(12)
    [2]=>
    int(1)
    [3]=>
    int(2)
  }

我将其留给OP来确定如何选择使用哪些序列来表示输入到该函数的所有月份。

答案 1 :(得分:2)

查看您的数据,我们会看到以下前提条件:

  1. 最大范围是1到12。
  2. 输入已排序,因此已订购。
  3. 只有一个地方发生环绕:从12到1。
  4. 考虑到这一点,我们可以说以下内容:

    1. 第一个值为1或没有环绕。
    2. 最后一个值为12或没有回绕。
    3. 如果有一个环绕,从头开始连续几个月(1,2,...)都会被包裹。
    4. 这是一个相对简单的功能:

      function group_months(array $months) {
          $count = count($months);
          if (!$count || $months[0] != 1 || $months[$count-1] != 12 || $count === 12) {
              return $months;
          }
          for ($size = 1; $months[$size] === $size+1;) {
              $size++;
          }
          return array_merge(array_slice($months, $size), range(1, $size));
      }
      

      或者在shift-push变体中(移动1,2,......结束):

      function group_months(array $months)
      {
          $count = count($months);
          if ($count && $count != 12 && $months[$count - 1] === 12) {
              for ($month = 1; $months[0] === $month; $month++) {
                  $months[] = array_shift($months);
              }
          }
          return $months;
      }
      

      或者在pop-unshift变体中(Move ..,11,12到前面):

      function group_months(array $months)
      {
          $count = count($months);
          if ($count-- && $count != 11 && $months[0] === 1) {
              for ($month = 12; $months[$count] === $month; $month--) {
                  array_unshift($months, array_pop($months));
              }
          }
          return $months;
      }
      

      如果您想要对数组中的数字进行分组,请查看已经有字符串输出解决方案的相关问题:

答案 2 :(得分:1)

我的PHP不够好写一个实现,但我很想知道这是否可以通过使用循环数组或链接列表结构。

首先,使用12个布尔元素创建这样的结构,通过将最终元素的next属性设置为第一个元素使其成为循环。相反,第一个previous元素设置为最终元素。这代表了您的“环绕式”日历。

然后,您可以读入数组,将“日历”的每个元素设置为true,其中元素索引出现在输入数组中。

然后围绕“日历”循环,直到找到true元素的最大连续序列。重复以找到任何较小的并将其作为数组输出。

希望这对你来说是一个可行的起点,我有兴趣看到有人在PHP中实现它!

答案 3 :(得分:1)

尝试下面的PHP函数。它适用于所有给出的3个例子:

<pre>
<?php
function split_months($array)
{
    // remove duplicate values, if any
    // sort the array in ascending order
    $array = array_unique($array);
    sort($array);

    $results = array();

    // loop until the array is empty
    while(!empty($array))
    {
        // extract the first entry of the array
        $entry = array_shift($array);

        if(empty($results))
            $results[] = array($entry);
        else
        {
            // find in which sub-array of $results $entry needs to be stored
            foreach($results as $index => $values)
            {
                // extract the last value
                $last = array_pop($values);

                // compare with $entry
                if($entry-1 == $last)
                {
                    $results[$index][] = $entry;
                    unset($entry);
                    break;
                }
            }

            // there was no sub-array to store $entry: store it in a new sub-array
            if(isset($entry))
            $results[] = array($entry);
        }
    }

    // if $results contain no array, or only one, there is nothing to optimize
    if(sizeof($results) <= 1)
        return $results;

    // lastly, search if one result sub-array is starting with "1", and another is ending with "12"
    // in that case, join these 2 sub-arrays in one
    foreach($results as $index => $values)
    {
        if($values[0] == 1)
            $index1 = $index;
        elseif($values[sizeof($values)-1] == 12)
            $index12 = $index;

        if(isset($index1) && isset($index12))
            break;
    }
    if(isset($index1) && isset($index12))
    {
            // merge both sub-arrays
        $results[$index12] = array_merge($results[$index12], $results[$index1]);
            // remove the sub-array starting with "1"
        unset($results[$index1]);
    }

    return $results;
}

$array1 = array(1,2,3);
$array2 = array(1,2,11,12);
$array3 = array(1,4,5,11,12);

print_r(split_months($array1));
print_r(split_months($array2));
print_r(split_months($array3));
?>
</pre>

输出将是:

Array
(
    [0] => Array
        (
            [0] => 1
            [1] => 2
            [2] => 3
        )

)
Array
(
    [1] => Array
        (
            [0] => 11
            [1] => 12
            [2] => 1
            [3] => 2
        )

)
Array
(
    [1] => Array
        (
            [0] => 4
            [1] => 5
        )

    [2] => Array
        (
            [0] => 11
            [1] => 12
            [2] => 1
        )

)

答案 4 :(得分:0)

我不确定你是否做得对。我的意思是你的第三个例子。 array(1, 2, 4, 5, 11, 12)你怎么能确定这些序列不是3月 - 2月,4月 - 5月和11月 - 12月的序列,也不是11月至2月和4月 - 5月的2个序列。是否有任何用户输入可以控制这些序列,或者是否有其他用户输入?