有效地分离数组

时间:2012-02-23 03:39:28

标签: php arrays

我正在处理一系列具有以下结构的数字的绝望噩梦:

数组中的奇数:NumberRepresenting周
数组中的偶数:NumberRepresenting Time

例如在数组中:

index : value
0 : 9
1 : 1
2 : 10
3 : 1

第1天(星期一)意味着9 + 10。

问题是,我有一个不可预测的数量,我需要弄清楚每天有多少“会话”。会话的规则是,如果他们在不同的一天,他们会自动不同的会话。如果它们彼此相邻,就像在示例9 + 10中那样算作单个会话。可以直接在彼此旁边的最大数量是3.在此之后,需要至少有1个会话中断来计算为新会话。

不幸的是,我们不能假设数据将被排序。它将始终遵循偶数/奇数模式,但可能不会将逻辑上彼此相邻的会话存储在数组中。

我需要弄清楚有多少会话。

到目前为止,我的代码如下:

for($i = 0; $i < (count($TimesReq)-1); $i++){
    $Done = false;
    if($odd = $i % 2 )
    {
    //ODD WeekComp
        if(($TimesReq[$i] != $TimesReq[$i + 2])&&($TimesReq[$i + 2] != $TimesReq[$i + 4])){
        $WeeksNotSame = true;
        }
    }
    else
        {
        //Even TimeComp

        if(($TimesReq[$i] != ($TimesReq[$i + 2] - 1))&& ($TimesReq[$i + 2] != ($TimesReq[$i + 4] - 1)))
        $TimesNotSame = true; 
        }
    if($TimesNotSame == true && $Done == false){
    $HowMany++; 
    $Done = true;
    }
    if($WeeksNotSame == true && $Done == false){
    $HowMany++;
    $Done = true; 
    }
$TimesNotSame = false;
$WeeksNotSame = false;
    }

然而,这并不完美。例如,如果你有一个会话,然后是一个休息,然后是一个双重会话,它就不起作用。它将此视为一个会话。

这可能正如您所猜测的那样,课程作业问题,但这不是教科书中的问题,它是我正在实施的时间表系统的一部分,并且需要使其正常工作。所以请不要以为我只是将我的作业复制并粘贴给你们!

非常感谢你!

正在使用新代码:

if (count($TimesReq) % 2 !== 0) {
//throw new InvalidArgumentException();
}

for ($i = 0; $i < count($TimesReq); $i += 2) {

    $time = $TimesReq[$i];
    $week = $TimesReq[$i + 1];

    if (!isset($TimesReq[$i - 2])) {
        // First element has to be a new session
        $sessions += 1;
                $StartTime[] = $TimesReq[$i];
                $Days[] = $TimesReq[$i + 1];
        continue;
    }

    $lastTime = $TimesReq[$i - 2];
    $lastWeek = $TimesReq[$i - 1];

    $sameWeek = ($week === $lastWeek);
    $adjacentTime = ($time - $lastTime === 1);
    if (!$sameWeek || ($sameWeek && !$adjacentTime)) {

    if(!$sameWeek){//Time
    $Days[] = $TimesReq[$i + 1];
            $StartTime[] = $TimesReq[$i];
            $looking = true;
    }
    if($sameWeek && !$adjacentTime){
    }
    if($looking && !$adjacentTime){
        $EndTime[] = $TimesReq[$i];
        $looking = false;           
    }
//Week      

        $sessions += 1;
    }
}

2 个答案:

答案 0 :(得分:1)

如果您希望在数据中表示单个会话总数,则每个会话以空格分隔(非连续时间或单独一天)。我认为这个功能可以为您提供结果:

function countSessions($data)
{
    if (count($data) % 2 !== 0) throw new InvalidArgumentException();

    $sessions = 0;
    for ($i = 0; $i < count($data); $i += 2) {
        $time = $data[$i];
        $week = $data[$i + 1];

        if (!isset($data[$i - 2])) {
            // First element has to be a new session
            $sessions += 1;
            continue;
        }

        $lastTime = $data[$i - 2];
        $lastWeek = $data[$i - 1];

        $sameWeek = ($week === $lastWeek);
        $adjacentTime = ($time - $lastTime === 1);
        if (!$sameWeek || ($sameWeek && !$adjacentTime)) {
            $sessions += 1;
        }
    }

    return $sessions;
}

$totalSessions = countSessions(array(
    9, 1,
    10, 1,
));

这当然假设数据已排序。如果不是,则需要先对其进行排序。这是一个替代实现,包括对未排序数据的支持。

function countSessions($data)
{
    if (count($data) % 2 !== 0) throw new InvalidArgumentException();

    $slots = array();
    foreach ($data as $i => $value) {
        if ($i % 2 === 0) $slots[$i / 2]['time'] = $value;
        else $slots[$i / 2]['week'] = $value;
    }

    usort($slots, function($a, $b) {
        if ($a['week'] == $b['week']) {
            if ($a['time'] == $b['time']) return 0;
            return ($a['time'] < $b['time']) ? -1 : 1;
        } else {
            return ($a['week'] < $b['week']) ? -1 : 1;
        }
    });

    $sessions = 0;
    for ($i = 0; $i < count($slots); $i++) {
        if (!isset($slots[$i - 1])) { // First element has to be a new session
            $sessions += 1;
            continue;
        }

        $sameWeek = ($slots[$i - 1]['week'] === $slots[$i]['week']);
        $adjacentTime = ($slots[$i]['time'] - $slots[$i - 1]['time'] === 1);
        if (!$sameWeek || ($sameWeek && !$adjacentTime)) {
            $sessions += 1;
        }
    }

    return $sessions;
}

答案 1 :(得分:0)

这是我尝试解决您的问题的小尝试。希望我明白你想要的东西:

$TimesReq = array(9,4,11,4,13,4,8,4,7,2,12,4,16,4,18,4,20,4,17,4);

// First just create weeks with all times lumped together 
$weeks = array();
for($tri=0; $tri<count($TimesReq); $tri+=2){
  $time = $TimesReq[$tri];
  $week = $TimesReq[$tri+1];

  $match_found = false;
  foreach($weeks as $wi=>&$w){
    if($wi==$week){
      $w[0] = array_merge($w[0], array($time));
      $match_found = true;
      break;
    }
  }
  if(!$match_found) $weeks[$week][] = array($time);
}

// Now order the times in the sessions in the weeks
foreach($weeks as &$w){
  foreach($w as &$s) sort($s);
}

// Now break up sessions by gaps/breaks
$breaking = true;
while($breaking){
  $breaking = false;
  foreach($weeks as &$w){
    foreach($w as &$s){
      foreach($s as $ti=>&$t){
        if($ti>0 && $t!=$s[$ti-1]+1){
          // A break was found
          $new_times = array_splice($s, $ti);
          $s = array_splice($s, 0, $ti);
          $w[] = $new_times;
          $breaking = true;
          break;
        }
      }
    }
  }
}

//print_r($weeks);

foreach($weeks as $wi=>&$w){
  echo 'Week '.$wi.' has '.count($w)." session(s):\n";
  foreach($w as $si=>&$s)
  {
    echo "\tSession ".($si+1).":\n";
    echo "\t\tStart Time: ".$s[0]."\n";
    echo "\t\tEnd Time: ".((int)($s[count($s)-1])+1)."\n";
  }
}

给定$TimesReq = array(9,4,11,4,13,4,8,4,7,2,12,4,16,4,18,4,20,4,17,4);代码将产生输出:

Week 4 has 4 session(s):
    Session 1:
        Start Time: 8
        End Time: 10
    Session 2:
        Start Time: 11
        End Time: 14
    Session 3:
        Start Time: 16
        End Time: 19
    Session 4:
        Start Time: 20
        End Time: 21
Week 2 has 1 session(s):
    Session 1:
        Start Time: 7
        End Time: 8

希望有所帮助。