I have an array of dates as input in the form YYYY-mm-dd=>category_id.0 (category_id counting from 0).$days =array (  '2014-10-15' => 49,  '2014-10-16' => 49,  '2014-10-17' => 49,  '2014-10-18' => 0,  '2014-10-19' => 0,  '2014-10-20' => 0,  '2014-10-21' => 0,  '2014-10-22' => 0,  '2014-10-23' => 0,  '2014-10-24' => 0,  '2014-10-25' => 0,  '2014-10-26' => 0,  '2014-10-27' => 0,  '2014-10-28' => 0,  '2014-10-29' => 0,  '2014-10-30' => 0,  '2014-10-31' => 0,  '2014-11-01' => 0,  '2014-11-02' => 0,  /* MISSING 2014-11-03 */  '2014-11-04' => 0,  '2014-11-05' => 0,  '2014-11-06' => 0,  '2014-11-07' => 0,  '2014-11-08' => 0,  '2014-11-09' => 0,  '2014-11-10' => 0,  '2014-11-11' => 0,  '2014-11-12' => 0,  '2014-11-13' => 0,  '2014-11-14' => 0,  '2014-11-15' => 0,  '2014-11-16' => 0,  '2014-11-17' => 0,  '2014-11-18' => 0,  '2014-11-19' => 0,  '2014-11-20' => 0,  '2014-11-21' => 0,  '2014-11-22' => 0,  '2014-11-23' => 0,  '2014-11-24' => 0,  '2014-11-25' => 0,  '2014-11-26' => 0,  '2014-11-27' => 0,  '2014-11-28' => 0,  '2014-11-29' => 0,  '2014-11-30' => 0,  '2014-12-01' => 0,  '2014-12-02' => 0,  '2014-12-03' => 0,  '2014-12-04' => 0,  '2014-12-05' => 0,  '2014-12-06' => 0,  '2014-12-07' => 0,  '2014-12-08' => 0,  '2014-12-09' => 0,  '2014-12-10' => 0,  '2014-12-11' => 0,  '2014-12-12' => 0,  '2014-12-13' => 0,  '2014-12-14' => 0,  '2014-12-15' => 0,  '2014-12-16' => 0,  '2014-12-17' => 0,  '2014-12-18' => 0,  '2014-12-19' => 0,  '2014-12-20' => 0,  '2014-12-21' => 0,  '2014-12-22' => 1,  '2014-12-23' => 3,  '2014-12-24' => 3,  '2014-12-25' => 3,  '2014-12-26' => 3,  '2014-12-27' => 3,  '2014-12-28' => 3,  '2014-12-29' => 50,  '2014-12-30' => 50,  '2014-12-31' => 50,  '2015-12-24' => 2,  '2015-12-25' => 2,);I want to build an array of range of dates grouped by category_id. For example, category_id 49 has 3 consecutive days from 15 to 17, so the first range should be:array('2014-10-15',2014-10-17',49).the category_id 0 start from 2014-10-18 and end to 2014-12-21 HOWEVER due the missing day 2014-11-03 I must split the range in two parts:array('2014-10-18','2014-11-02',0) and array('2014-11-04','2014-12-21',0)The final output is an array of ranges like this:Array(    [0] => Array        (            [0] => 2014-10-15            [1] => 2014-10-17            [2] => 49        )    [1] => Array        (            [0] => 2014-10-18            [1] => 2014-11-02            [2] => 0        )    [3] => Array        (            [0] => 2014-11-04            [1] => 2014-12-21            [2] => 0        )    [4] => Array        (            [0] => 2014-12-22            [1] => 2014-12-22            [2] => 1        )    [5] => Array        (            [0] => 2014-12-23            [1] => 2014-12-28            [2] => 3        )    [6] => Array        (            [0] => 2014-12-29            [1] => 2014-12-31            [2] => 50        )    [8] => Array        (            [0] => 2015-12-24            [1] => 2015-12-25            [2] => 2        ))Due the possibility of to have holes in days array, I tought that the best way is to get the first day (in temporary order), then add a day for each cycle.Checking the values, I build the range array.function get_range_from_days($days) {    // check if input is empty    if(count($days) == 0) return array();    // output to fill    $ranges = array();    // order dates keys in order to have the first date in temporary order    ksort($days);    // get first and last day    $firstday = key($days);    end($days);    $lastday = key($days);    // get the type of first day (actually the current day where we looks)    $current_type = $days[$firstday];    // using datetime object for easy step of 1 day    $datetime = new \DateTime($firstday);    $datetime->setTime(9,0,0); // avoid time problems at midnight (it's needed?)    // do the first step outside the while    $datetime->add(new DateInterval('P1D'));    // store old value of day    $oldday = $firstday;    // build the first range    $ranges[] = array($firstday,null,$current_type);    while(($day = $datetime->format('Y-m-d')) <= $lastday) {        // if there are holes, fill it with null        if(!isset($days[$day])) {            $days[$day] = null;        }        // check if type has changed (=>need new range)        if(($days[$day] !== $current_type)) {            $ranges[count($ranges)-1][1] = $oldday;            $ranges[] = array($day,null,$days[$day]);            $current_type = $days[$day];        }            // store previous day        $oldday = $day;            // next day        $datetime->add(new DateInterval('P1D'));    }    // complete the last range    $ranges[count($ranges)-1][1] = $lastday;    // remove range of holes    foreach($ranges as $k=>$range) {        if(is_null($range[2])) {            unset($ranges[$k]);        }    }    return $ranges;}Any improvements? This looks not so nice.
Get ranges from array of days
php
This is the way I would do it:function getRangeFromDays($days) {  // collect dates into catagories  foreach ($days as $date => $catagory) {    $temp[$catagory][] = $date;  }  // process all dates in each catagory  foreach ($temp as $catagory => $dates) {    sort($dates);    $startDate  = $dates[0];    $finishDate = array_pop($dates);    // walk through the dates, breaking at gaps    foreach ($dates as $key => $date)    if (($key > 0) && (strtotime($date)-strtotime($dates[$key-1]) > 99999)) {      $result[] = array($startDate,$dates[$key-1],$catagory);      $startDate = $date;    }    // force the end    $result[] = array($startDate,$finishDate,$catagory);  }  return $result;}echo '<pre>';print_r(getRangeFromDays($days));echo '</pre>';I use an intermediate array which makes it easier to get the results because it's already segmented by catagory. All that's then left to do is the date ranges. I turn dates into seconds to see if the gap is bigger than one day (> 99999 seconds).