2

I would like to implode an array, but with one difference. I would like to merge intervals with a - sign. How can this be done? (The array is ordered!)

Examples:

array(1,2,3,6,8,9) => "1-3,6,8-9"
array(2,4,5,6,8,10) => "2,4-6,8,10"
mickmackusa
  • 43,625
  • 12
  • 83
  • 136
Iter Ator
  • 8,226
  • 20
  • 73
  • 164
  • 3
    There is no php function that can do that for you. You would need to write your own script. – KiwiJuicer Nov 23 '15 at 15:00
  • 1
    It is as @Kiwi Juicer says. You could do this quite simply with a foreach() loop if you spend some time thinking about it. Consider what steps you need to do to detect and consolidate intervals. – Andrea Nov 23 '15 at 15:13

4 Answers4

8

This should work for you:

First for every iteration we simply append the current number of the iteration to the $result string:

$result .= $arr[$i];

After this we check in a while loop if there exists a next element in the array(1) and it follows up the number from the current iteration(2). We do that until the condition evaluates as false:

//(1)Check if next element exists     (2)Check if next element follows up the prev one
      ┌───────┴───────┐    ┌───────────┴────────────┐      
while(isset($arr[$i+1]) && $arr[$i] + 1 == $arr[$i+1] && ++$range)
    $i++;

Then we check if we have a range (e.g. 1-3) or not. If yes then we append the dash and the end number of the range to the result string:

if($range)
    $result .= "-" . $arr[$i];

At the end we also check if we are at the end of the array and don't need to append a comma anymore:

if($i+1 < $l)
    $result .= ",";

Code:

<?php

    $arr = array(1,2,3,6,8,9);
    $result = "";
    $range = 0;

    for($i = 0, $l = count($arr); $i < $l; $i++){

        $result .= $arr[$i];

        while(isset($arr[$i+1]) && $arr[$i] + 1 == $arr[$i+1] && ++$range)
            $i++;

        if($range)
            $result .= "-" . $arr[$i];

        if($i+1 < $l)
            $result .= ",";

        $range = 0;   

    }

    echo $result;

?>

output:

1-3,6,8-9
Rizier123
  • 58,877
  • 16
  • 101
  • 156
2
    $oldArray=array(2,4,5,6,8,10);

    $newArray=array();


    foreach($oldArray as $count=>$val){
        if($count==0){
            //begin sequencing
            $sequenceStart=$sequenceEnd=$val;
        }

        if($val==$sequenceEnd+1){
            $sequenceEnd=$val;
            continue;
        }else{
            if($sequenceEnd==$val){
                //do nothing
                continue;
            }


        }

        //new sequence begins 
        //save new sequence
        if($sequenceStart==$sequenceEnd){
            //sequnce is a single number
            $newArray[]=$sequenceEnd;
        }else{
            $newArray[]=$sequenceStart.'-'.$sequenceEnd;
        }

        //reset sequence
        $sequenceStart=$sequenceEnd=$val;
    }

    //new sequence begins 
    //save new sequence
    if($sequenceStart==$sequenceEnd){
        //sequnce is a single number
        $newArray[]=$sequenceEnd;
    }else{
        $newArray[]=$sequenceStart.'-'.$sequenceEnd;
    }

    //reset sequence
    $sequenceStart=$sequenceEnd=$val;



    return implode(',', $newArray);
  • 2
    While this code snippet may solve the question, [including an explanation](http://meta.stackexchange.com/questions/114762/explaining-entirely-‌​code-based-answers) out of the code really helps to improve the quality of your post. Remember that you are answering the question for readers in the future, and those people might not know the reasons for your code suggestion. Please also try not to crowd your code with explanatory comments, this reduces the readability of both the code and the explanations! – Rizier123 Nov 23 '15 at 15:17
0

There is no function like this, therefore you will need to create one yourself. I just created a sample function how this may look like, there are many possible solution for this (Did not try if it actually works, as I do not have a webserver in reach atm)

<?php
function implodeNumberArray($arr) {
 $lastValue = NULL;
 $o = "";
 //For each value in array
 foreach ($arr as $v) {
  if(!is_null($lastValue)) {
   //If the number is following, do not paste it
   if(($lastValue+1) == $v) {
    //Check if the - sign was already posted
    if(!(stripos(strrev($o), '-') === 0)) {
     // - sign not pasted, therefore paste it
     $o .= "-";
    }
   } else {
    //Check if there is a - sign at the end
    if((stripos(strrev($o), '-') === 0)) {
     // Has - => paste 'prevValue,value''
     $o .= $lastValue . "," . $v;
    } else {
     //Check if there is a , sign at the end
     if((stripos(strrev($o), ',') === 0)) {
      // No - but , => paste 'value'
      $o .= $v;
     } else {
      // No - and no , => paste ',value'
      $o .= ",".$v;
     }         
    }
   }
  } else {
   $o = $v;
  }

  $lastValue = $v;
 }
 //Check if the implode has the last number set correctly
 if((stripos(strrev($o), '-') === 0)) {
  $o .= $lastValue;
 }
 return $o;
}

echo implodeNumberArray(array(1,2,3,6,8,9));
?>
Xavjer
  • 8,838
  • 2
  • 22
  • 42
0

Similar to the answer @ Reduce array of month names by creating hyphenated expressions from consecutive months

Push a number as a reference into the result array if the array is empty or the number does not immediately follow the previous number.

When consecutive numbers are encountered, rebuild the reference string by preserving the leading number and appending a new hyphen and the new number.

One loop and one conditional expression is all that is needed.

Code: (Demo)

function hyphenatedRanges(array $numbers): string
{
    $result = [];
    foreach ($numbers as $i => $number) {
        if (isset($ref) && $number === $numbers[$i - 1] + 1) {
            $ref = strtok($ref, "-") . "-$number";
        } else {
            unset($ref);
            $ref = $number;
            $result[] = &$ref;
        }
    }
    return implode(',', $result);
}

echo hyphenatedRanges([1, 2, 3, 6, 8, 9]) . "\n"; // "1-3,6,8-9"
echo hyphenatedRanges([2, 4, 5, 6, 8, 10]); // "2,4-6,8,10"
mickmackusa
  • 43,625
  • 12
  • 83
  • 136