12

I'm trying to normalize/expand/hydrate/translate a string of numbers as well as hyphen-separated numbers (as range expressions) so that it becomes an array of integer values.

Sample input:

$array = ["1","2","5-10","15-20"];

should become :

$array = [1,2,5,6,7,8,9,10,15,16,17,18,19,20];

The algorithm I'm working on is:

//get the array values with a range in it :
$rangeArray = preg_grep('[-]',$array);

This will contain ["5-10", "16-20"]; Then :

foreach($rangeArray as $index=>$value){
    $rangeVal = explode('-',$value);
    $convertedArray = range($rangeVal[0],$rangeVal[1]);
}

The converted array will now contain ["5","6","7","8","9","10"];

The problem I now face is that, how do I pop out the value "5-10" in the original array, and insert the values in the $convertedArray, so that I will have the value:

$array = ["1","2",**"5","6","7","8","9","10"**,"16-20"];

How do I insert one or more values in place of the range string? Or is there a cleaner way to convert an array of both numbers and range values to array of properly sequenced numbers?

mickmackusa
  • 43,625
  • 12
  • 83
  • 136
muffin
  • 2,034
  • 10
  • 43
  • 79
  • 2
    [array_splice()](http://www.php.net/manual/en/function.array-splice.php) is the function you're asking for, though you could also use [array_merge()](http://www.php.net/manual/en/function.array-merge.php) if you don't care about the order of entries – Mark Baker Jul 02 '15 at 09:10
  • could you provide an example on how i could use it in my case? – muffin Jul 02 '15 at 09:10
  • i tried array merge, but then I'd have to eliminate those with "5-10" and other range values, and then insert the "normalized" values in the index of that range string. – muffin Jul 02 '15 at 09:13
  • Combine `array_splice` with [`range()`](http://php.net/manual/en/function.range.php) and you should be able to do what you wish. – Andrei Jul 02 '15 at 09:15

8 Answers8

4

Here you go. I tried to minimize the code as much as i can.

Consider the initial array below,

$array = ["1","2","5-10","15-20"];

If you want to create a new array out of it instead $array, change below the first occurance of $array to any name you want,

$array = call_user_func_array('array_merge', array_map(function($value) {
            if(1 == count($explode = explode('-', $value, 2))) {
                return [(int)$value];
            }
            return range((int)$explode[0], (int)$explode[1]);
        }, $array));

Now, the $array becomes,

$array = [1,2,5,6,7,8,9,10,15,16,17,18,19,20];

Notes:

  • Casts every transformed member to integer
  • If 15-20-25 is provided, takes 15-20 into consideration and ignores the rest
  • If 15a-20b is provided, treated as 15-20, this is result of casing to integer after exploded with -, 15a becomes 15
  • Casts the array keys to numeric ascending order starting from 0
  • New array is only sorted if given array is in ascending order of single members and range members combined
viral
  • 3,724
  • 1
  • 18
  • 32
3

Try this:

<?php
$array = ["1","2","5-10","15-20"];

$newdata = array();
foreach($array as $data){
    if(strpos($data,'-')){

        $range = explode('-', $data);
        for($i=$range[0];$i<=$range[1];$i++){
            array_push($newdata, $i);
        }
    }
    else{
        array_push($newdata, (int)$data);
    }

}

        echo "<pre>";
print_r($array);
        echo "</pre>";
        echo "<pre>";
print_r($newdata);
        echo "</pre>";

Result:

Array
(
    [0] => 1
    [1] => 2
    [2] => 5-10
    [3] => 15-20
)
Array
(
    [0] => 1
    [1] => 2
    [2] => 5
    [3] => 6
    [4] => 7
    [5] => 8
    [6] => 9
    [7] => 10
    [8] => 15
    [9] => 16
    [10] => 17
    [11] => 18
    [12] => 19
    [13] => 20
)

Problem solved!

Josua Marcel C
  • 3,122
  • 6
  • 45
  • 87
2

Simpler and shorter answer.

See in Ideone

$new_array = array();  

foreach($array as $number){
  if(strpos($number,'-')){
     $range = explode('-', $number);  
     $new_array = array_merge($new_array, range($range[0],$range[1]));
  } 
  else{
     $new_array[] = (int) $number;
  }
}

var_dump($new_array);
Muhammet
  • 3,288
  • 13
  • 23
2

Using range and array_merge to handle the non-numeric values:

$array = ["1","2","5-10","15-20"];

$newArray = [];
array_walk(
    $array,
    function($value) use (&$newArray) {
        if (is_numeric($value)) {
            $newArray[] = intval($value);
        } else {
            $newArray = array_merge(
                $newArray,
                call_user_func_array('range', explode('-', $value))
            );
        }
    }
);

var_dump($newArray);
Mark Baker
  • 209,507
  • 32
  • 346
  • 385
2

It's easier to find out the minimum and maximum value and create the array with them. Here's an example:

$in = ["1","2","5-10","15-20"];
$out = normalizeArray($in);
var_dump($out);

function normalizeArray($in)
{
    if(is_array($in) && sizeof($in) != 0)
    {
        $min = null;
        $max = null;
        foreach($in as $k => $elem)
        {
            $vals = explode('-', $elem);
            foreach($vals as $i => $val)
            {
                $val = intval($val);
                if($min == null || $val < $min)
                {
                    $min = $val;
                }
                if($max == null || $val > $max)
                {
                    $max = $val;
                }
            }
        }

        $out = array();
        for($i = $min; $i <= $max; $i++)
        {
            $out[] = $i;
        }

        return $out;
    }
    else
    {
        return array();
    }
}
udAL
  • 43
  • 8
2

here you go mate.

<?php
$array = ["1","2","5-10","15-20"];
$newArr = array();
foreach($array as $item){
    if(strpos($item, "-")){
        $temp = explode("-", $item);
        $first = (int) $temp[0];
        $last = (int) $temp[1];
        for($i = $first; $i<=$last; $i++){
            array_push($newArr, $i);
        }
    }
    else
        array_push($newArr, $item);
}
print_r($newArr);
?>
Muhammad Husnain Tahir
  • 1,009
  • 1
  • 15
  • 28
1

try this:

$array = ["1","2","5-10","15-20"];
$result = [];

foreach ($array as $a) {
    if (strpos($a,"-")!== false){
        $tmp = explode("-",$a);
        for ($i = $tmp[0]; $i<= $tmp[1]; $i++) $result[] = $i;
    } else {
        $result[] = $a;
    }
}

var_dump($result);
1

you did not finish a little

$array = ["1","2","5-10","15-20"];
// need to reverse order else index will be incorrect after inserting
$rangeArray = array_reverse( preg_grep('[-]',$array), true);

$convertedArray = $array;

foreach($rangeArray as $index=>$value) {

    $rangeVal = explode('-',$value);
    array_splice($convertedArray, $index, 1, range($rangeVal[0],$rangeVal[1]));
}

print_r($convertedArray);
splash58
  • 26,043
  • 3
  • 22
  • 34