2012-02-23 1 views
1

Je vais avoir un cauchemar asbolute face à un tableau de nombres qui a la structure suivante:Ventiler une gamme efficace

Les nombres impairs dans le tableau: NumberRepresenting Semaine
Même numéros dans le tableau: NumberRepresenting temps

Ainsi, par exemple dans le tableau:

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

Signifiera 9 + 10 le jour 1 (lundi). Le problème est, j'ai un nombre imprévisible de ceux-ci et je dois déterminer combien de "sessions" il y a par jour. Les règles d'une session sont que si elles sont un autre jour, elles sont automatiquement différentes. Si elles sont côte à côte comme dans l'exemple 9 + 10 cela compterait comme une seule session. Le nombre maximal pouvant être directement l'un à côté de l'autre est de 3. Après cela, il doit y avoir un minimum d'une pause entre deux sessions pour compter comme une nouvelle session.

Malheureusement, nous ne pouvons pas supposer que les données seront triées. Il suivra toujours le modèle pair/impair MAIS ne pourrait pas avoir des sessions stockées côte à côte logiquement dans le tableau.

Je dois déterminer combien de sessions il y a.

Mon code à ce jour est le suivant:

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; 
    } 

Cependant, cela ne fonctionne pas parfaitement. par exemple, cela ne fonctionne pas si vous avez une seule session, puis une pause, puis une double session. Cela compte comme une session. Ceci est, probablement comme vous l'avez deviné, un problème de cours, mais ce n'est pas une question d'un manuel, il fait partie d'un système de planification que je suis en train de mettre en œuvre et est nécessaire pour le faire fonctionner. Alors s'il te plait ne pense pas que je suis juste en train de copier et coller mes devoirs à vous les gars!

Merci beaucoup!

Nouveau code utilisé:

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; 
    } 
} 
+1

Qu'est-ce qui est censé se produire lorsque les données donnent 4 semaines d'affilée? Est-ce que cela devrait être reconnu comme 2 sessions, ou le code devrait-il reconnaître que l'exigence (avoir seulement 3 sessions d'affilée) est cassée? – ghbarratt

+0

Une validation préalable signifie que cela ne se produira pas. Désolé aurait dû être plus précis. Le maximum sera 3 d'affilée jusqu'à une pause. – user1096685

+0

Vous indiquez que même les index (0 et 2 dans votre exemple) représentent des semaines, mais que plus tard les 9 + 10 seraient la même session (il n'y a donc qu'une seule session dans votre exemple), mais s'ils sont des semaines ils sont des sessions séparées? (à l'heure = 1 à la semaine 9 et à l'heure = 1 à la semaine 10). Ou suis-je complètement confus? Aussi, vous parlez des jours, mais il n'y a pas de données sur les jours. Les jours/semaines sont-ils utilisés de manière interchangeable? –

Répondre

1

Si vous voulez un nombre total de sessions représentées dans les données, où chaque session est séparée par un espace (soit un temps non contigus, ou un autre jour). Je pense que cette fonction vous obtiendra votre résultat:

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, 
)); 

Ceci bien sûr suppose que les données sont triées. Si ce n'est pas le cas, vous devrez le trier en premier. Voici une autre implémentation qui inclut la prise en charge des données non triées.

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; 
} 
+0

Merci pour ça. Ce qui fonctionne mieux que mon code, mais il a le même problème fondamental que mon code avait. Lequel, je n'ai jamais vraiment considéré avant votre réponse. Les données pourraient éventuellement ne pas être triées. – user1096685

+0

S'il y a une possibilité de trier des données, je pense que la meilleure solution est de les trier d'abord. Évidemment, en gardant les paires temps/semaine attachées. Ce serait probablement plus facile que d'essayer de garder une trace de toutes les sessions à la fois. –

+0

Bon point. Votre fonction est beaucoup plus facile à suivre dans mon esprit que le mien, alors maintenant je peux mettre en œuvre le tri et courir avec de petits problèmes. Merci beaucoup. – user1096685

0

Voici ma petite tentative pour résoudre votre problème. Espérons que je comprends ce que vous voulez:

$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"; 
    } 
} 

Étant donné le code $TimesReq = array(9,4,11,4,13,4,8,4,7,2,12,4,16,4,18,4,20,4,17,4); produira en sortie:

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 

espoir qui aide.