我有一个数月(数字,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
任何想法如何做到这一点?
答案 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)
查看您的数据,我们会看到以下前提条件:
考虑到这一点,我们可以说以下内容:
这是一个相对简单的功能:
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个序列。是否有任何用户输入可以控制这些序列,或者是否有其他用户输入?