Aggregate array values into ranges In five minutes I made a pretty ugly looking function. Can you help before I have to commit the code into history?


  Requirements:
  
  I would like a function that takes an array of numbers, and returns an
  array of ranges. Ideally remove the duplicate line.
  
  Sample Input:
  
  

Array(1,2,3,4,5,6,10,11,12,13,20,24)

  
  Output:

Array
(
    [0] =&gt; 1-6
    [1] =&gt; 10-13
    [2] =&gt; 20
    [3] =&gt; 24
)

  
  Winning Entries:

Pseudo code  
PHP



My attempt:



$myArray = array(1,2,3,4,5,6,10,11,12,13,20,24);

$rangeArray = array();
$start = $end = current($myArray);
foreach($myArray as $range){
    if($range - $end &gt; 1){
        $rangeArray[] = ($start == $end)?$start:$start."-".$end;
        $start = $range;
    }

    $end = $range;
}
$rangeArray[] = ($start == $end)?$start:$start."-".$end;

print_r($rangeArray);
While these may not be any shorter or more efficient than existing answers, perhaps with a slightly different approach they still bring something to the table and might be considered a little less 'ugly'.

Essentially the GetRanges function I've written does the following:


Take a parameter-supplied array of numbers ($aNumbers), remove any duplicates from the array and then sort them numerically lowest to highest.
We next create a multi-dimensional array ($aGroups) and working sequentially through the array of numbers ($aNumbers): Except for the first number which we just add to $aGroups to get us started, for each consecutive number $i &gt; 0, if the previous number $aNumbers[$i-1] is equal to the current number minus 1 $aNumbers[$i] - 1 then the current number is added to the same group because its consecutive and belongs to that range, otherwise the current number is added to $aGroups as a new sub-array with one entry array( $aNumbers[$i] ).


For options 2 and 3 where the function is expanded upon for a simple array:


A new array ($aRanges) is created and for each $aGroups record, if the first entry of the sub-array is the only entry then a new entry is added to $aRanges for just this number, otherwise a new entry is added to $aRanges specifying the first number in the range followed by a hyphen followed by the last number in the range.


For option 3 where the function is expanded upon to return a string:


The implode function is used to create a comma-separated list of all the entries in the $aRanges array and return this as a string.




Option 1: If you want your function to return a multi-dimensional array:

&lt;?php
function GetRanges( $aNumbers ) {
  $aNumbers = array_unique( $aNumbers );
  sort( $aNumbers );
  $aGroups = array();
  for( $i = 0; $i &lt; count( $aNumbers ); $i++ ) {
    if( $i &gt; 0 &amp;&amp; ( $aNumbers[$i-1] == $aNumbers[$i] - 1 ))
      array_push( $aGroups[count($aGroups)-1], $aNumbers[$i] );
    else
      array_push( $aGroups, array( $aNumbers[$i] )); 
  }
  return $aGroups;
}

$aNumbers = array( 1, 2, 3, 4, 5, 6, 10, 11, 12, 13, 20, 24 );
print_r( GetRanges( $aNumbers ));



  Output:

Array (
  [0] =&gt; Array ( [0] =&gt; 1, [1] =&gt; 2, [2] =&gt; 3, [3] =&gt; 4, [4] =&gt; 5, [5] =&gt; 6 )
  [1] =&gt; Array ( [0] =&gt; 10, [1] =&gt; 11, [2] =&gt; 12, [3] =&gt; 13 )
  [2] =&gt; Array ( [0] =&gt; 20 )
  [3] =&gt; Array ( [0] =&gt; 24 )
)



Option 2: If you want your function to return a simple array:

&lt;?php
function GetRanges( $aNumbers ) {
  $aNumbers = array_unique( $aNumbers );
  sort( $aNumbers );
  $aGroups = array();
  for( $i = 0; $i &lt; count( $aNumbers ); $i++ ) {
    if( $i &gt; 0 &amp;&amp; ( $aNumbers[$i-1] == $aNumbers[$i] - 1 ))
      array_push( $aGroups[count($aGroups)-1], $aNumbers[$i] );
    else
      array_push( $aGroups, array( $aNumbers[$i] )); 
  }
  $aRanges = array();
  foreach( $aGroups as $aGroup ) {
    if( count( $aGroup ) == 1 )
      $aRanges[] = $aGroup[0];
    else
      $aRanges[] = $aGroup[0] . '-' . $aGroup[count($aGroup)-1];
  }
  return $aRanges;
}

$aNumbers = array( 1, 2, 3, 4, 5, 6, 10, 11, 12, 13, 20, 24 );
print_r( GetRanges( $aNumbers ));



  Output: Array ( [0] =&gt; 1-6, [1] =&gt; 10-13, [2] =&gt; 20, [3] =&gt; 24 )


Option 3: If you want your function to return a string:

&lt;?php
function GetRanges( $aNumbers ) {
  $aNumbers = array_unique( $aNumbers );
  sort( $aNumbers );
  $aGroups = array();
  for( $i = 0; $i &lt; count( $aNumbers ); $i++ ) {
    if( $i &gt; 0 &amp;&amp; ( $aNumbers[$i-1] == $aNumbers[$i] - 1 ))
      array_push( $aGroups[count($aGroups)-1], $aNumbers[$i] );
    else
      array_push( $aGroups, array( $aNumbers[$i] )); 
  }
  $aRanges = array();
  foreach( $aGroups as $aGroup ) {
    if( count( $aGroup ) == 1 )
      $aRanges[] = $aGroup[0];
    else
      $aRanges[] = $aGroup[0] . '-' . $aGroup[count($aGroup)-1];
  }
  return implode( ',', $aRanges );
}

$aNumbers = array( 1, 2, 3, 4, 5, 6, 10, 11, 12, 13, 20, 24 );
echo( GetRanges( $aNumbers ));



  Output:
  1-6,10-13,20,24