Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>What you are looking for has nothing to do with permutations. You are considering overlapping time periods, and I see two approaches:</p> <ol> <li>Pre-process all your time-periods into a timeline, then query the timeline, or</li> <li>Scan through all your resource-blocks in parallel.</li> </ol> <p>The first option takes more memory but is easier to understand; the second is potentially less resource-hungry but much more complicated to program. Both would benefit from minimizing the dataset to be considered, ie limit the target time period.</p> <p>Option #1 is as follows (implemented in OO PHP5):</p> <pre><code>&lt;?php class Resource { protected $name; // resource ID protected $start; // start timestamp protected $finish; // end timestamp // resource available while $start &lt;= current time &lt; $end function __construct($n, $sd, $st, $ed, $et) { $this-&gt;name = $n; $this-&gt;start = strtotime("$sd $st"); $this-&gt;finish = strtotime("$ed $et"); } function getID() { return $this-&gt;name; } function getStart() { return $this-&gt;start; } function getEnd() { return $this-&gt;finish; } } class Timeline { protected $times; // ordered list of start-times; protected $resources; // resources available in each timeslot protected $offs; // iterator offset function __construct() { $this-&gt;times = array(); $this-&gt;resources = array(); $this-&gt;offs = 0; } // binary search, insert if not found, return index private function time_ins($time) { // array is empty? if (count($this-&gt;times) == 0) { $this-&gt;times[0]= $time; $this-&gt;resources[0] = array(); return 0; } $min = $lo = 0; $max = $hi = count($this-&gt;times)-1; // binary search while($lo &lt;= $hi) { $mid = ($lo+$hi) &gt;&gt; 1; if ($this-&gt;times[$mid] == $time) { // already exists - return index return $mid; } elseif ($this-&gt;times[$mid] &lt; $time) { // if value exists, is in upper half of array $lo = $mid+1; if ($lo &gt; $max || $this-&gt;times[$lo] &gt; $time) { // $lo points to first value greater than $time // insert new value at $lo array_splice($this-&gt;times, $lo, 0, $time); $t = isset($this-&gt;resources[$lo-1]) ? $this-&gt;resources[$lo-1] : array(); array_splice($this-&gt;resources, $lo, 0, $t); return $lo; } } else { // if value exists, is in lower half of array $hi = $mid-1; if ($hi &lt; $min || $this-&gt;times[$hi] &lt; $time) { // $hi points to first value less than $time // insert new value at $hi+1 array_splice($this-&gt;times, $hi+1, 0, $time); $t = isset($this-&gt;resources[$hi+1]) ? $this-&gt;resources[$hi+1] : array(); array_splice($this-&gt;resources, $hi+1, 0, $t); return $hi+1; } } } } function Add( $start, $end, $id ) { $s = $this-&gt;time_ins($start); $e = $this-&gt;time_ins($end); for($i = $s; $i &lt; $e; ++$i) $this-&gt;resources[$i][]= $id; } function reset() { $offs = 0; } function isValid() { return ($this-&gt;offs+1 &lt; count($this-&gt;times)); } // omit last time (is end-time only) function next() { $this-&gt;offs++; } function resCount() { return count( $this-&gt;resources[ $this-&gt;offs ] ); } function getStart() { return $this-&gt;times[$this-&gt;offs]; } function getEnd() { return $this-&gt;times[$this-&gt;offs + 1]; } function getRes() { return $this-&gt;resources[$this-&gt;offs]; } } $res = array(); $res[]= new Resource('10', '2008-05-14', '08:00', '2008-05-14', '08:10'); $res[]= new Resource('10', '2008-05-14', '08:10', '2008-05-14', '08:20'); $res[]= new Resource('10', '2008-05-14', '08:20', '2008-05-14', '08:30'); $res[]= new Resource('13', '2008-05-14', '08:00', '2008-05-14', '08:10'); $res[]= new Resource('13', '2008-05-14', '08:10', '2008-05-14', '08:20'); $res[]= new Resource('13', '2008-05-14', '08:30', '2008-05-14', '08:40'); $tl = new Timeline(); foreach($res as $R) $tl-&gt;Add( $R-&gt;getStart(), $R-&gt;getEnd(), $R-&gt;getID() ); $needed = 2; $_pre = "\n&lt;p&gt;"; $_post = "&lt;/p&gt;"; for( $tl-&gt;reset(); $tl-&gt;isValid(); $tl-&gt;next() ) { $cnt = $tl-&gt;resCount(); if ($cnt &gt;= $needed) { $st = date("Y-m-d H:i", $tl-&gt;getStart()); $fn = date("Y-m-d H:i", $tl-&gt;getEnd()); $res = join(', ', $tl-&gt;getRes()); echo ($cnt == $needed ? "{$_pre}Available from $st to $fn using resources ($res){$_post}" : "{$_pre}Available from $st to $fn using any $needed of resources ($res){$_post}" ); } } ?&gt; </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload