3

I want to separate a PHP array when they have a common prefix.

$data = ['status.1', 'status.2', 'status.3',
         'country.244', 'country.24', 'country.845',
         'pm.4', 'pm.9', 'pm.6'];

I want each of them in separate variables like $status, $countries, $pms which will contain:

$status = [1,2,3];
$country = [244, 24, 845]
$pms = [4,9,6]

My Current code is taking 1.5 seconds to group them:

$statuses = [];
$countries = [];
$pms = [];
$start = microtime(true);
foreach($data as $item){
    if(strpos($item, 'status.') !== false){
        $statuses[]= substr($item,7);
    }

    if(strpos($item, 'country.') !== false){
        $countries[]= substr($item,8);
    }

    if(strpos($item, 'pm.') !== false){
        $pms[]= substr($item,3);
    }
}
$time_elapsed_secs = microtime(true) - $start;
print_r($time_elapsed_secs);

I want to know if is there any faster way to do this

3
  • 1
    Will you have only those 3 prefix or it is dynamic prefixs? Commented Dec 24, 2018 at 14:44
  • You can use asort($data) to improve loop performance Commented Dec 24, 2018 at 14:55
  • 1
    I will have 5 prefixes like status, country, pm, study type and date. Commented Dec 24, 2018 at 15:31

7 Answers 7

5

This will give you results for more dynamic prefixs - first explode with the delimiter and then insert by the key to result array.

For separating the value you can use: extract

Consider the following code:

$data = array('status.1','status.2','status.3', 'country.244', 'country.24', 'country.845', 'pm.4','pm.9', 'pm.6');

$res = array();
foreach($data as $elem) {
    list($key,$val) = explode(".", $elem, 2);
    $res[$key][] = $val;

}
extract($res); // this will separate to var with the prefix name

echo "Status is: " . print_r($status); // will output array of ["1","2","3"]

This snippet took less the 0.001 second...

Thanks @mickmackusa for the simplification

Sign up to request clarification or add additional context in comments.

Comments

3

Add continue to each of the if's, so if it's one of them, it won't then run the other ones... not really needed in the last one as obviously the loops starts again anyway. Should save a tiny bit of time, but doubt it'll be as much as you probably want to save.

foreach($data as $item){
    if(strpos($item, 'status.') !== false){
        $statuses[]= substr($item,7);
        continue;
    }

    if(strpos($item, 'country.') !== false){
        $countries[]= substr($item,8);
       continue;
    }

    if(strpos($item, 'pm.') !== false){
        $pms[]= substr($item,3);
        continue;
    }
}

Comments

3

I'd use explode to split them.

something like this:

$arr = array("status" => [],"country" => [],"pm" => []);
foreach($data as $item){
    list($key,$val) = explode(".",$item);
    $arr[$key][] = $val;
}
extract($res); // taken from david's answer

and it's a much more readable code (in my opinion)

___ EDIT ____

as @DavidWinder commented, this is both not dynamic and will not result in different variables - look at his answer for the most complete solution for your question

2 Comments

Notice this ignore the OP request of: "I want each of them in separate variables" - add using extract in your answer (I tried to answer this more dynamically...)
@DavidWinder - correct, your's is the most complete answer
1

You can push data into their respective groups while destructuring. The only iterated function call is explode().

Creating individual variables for each group is a design flaw / mismanagement of array data.

Code: (Demo)

$result = [];
foreach ($data as $value) {
    [$prefix, $result[$prefix][]] = explode('.', $value, 2);
}
var_export($result);

Output:

array (
  'status' => 
  array (
    0 => '1',
    1 => '2',
    2 => '3',
  ),
  'country' => 
  array (
    0 => '244',
    1 => '24',
    2 => '845',
  ),
  'pm' => 
  array (
    0 => '4',
    1 => '9',
    2 => '6',
  ),
)

Use sscanf() if you want to directly/explicitly cast the numeric values as integers. Demo

Comments

0

Use Explode. Also is a good way to use $limit param for performance and avoiding wrong behavior on having other '.' in values.

$arr = [];
foreach($data as $item){
    list($key,$val) = explode('.', $item, 2);
    if (!$key || !$val) continue;
    $arr[$key][] = $val;
}
var_dump($arr); 

Comments

0

If it was me I would do it like so...

<?php

$data = array ('status.1', 'status.2', 'status.3',
         'country.244', 'country.24', 'country.845',
         'pm.4', 'pm.9', 'pm.6');

$out = array ();

foreach ( $data AS $value )
{
    $value = explode ( '.', $value );

    $out[$value[0]][] = $value[1];
}

print_r ( $out );

?>

Comments

0

I'm not sure if this'll boost the performance but you could re-arrange your array in a way that each row has a heading and the corresponding value and then use array_column() to group which data you want.

This is an example of how you could group your data in such a way. (PHP 7.1.25+)

$groupedData = array_map(function($arg) {
    [$key, $val] = explode('.', $arg); # for PHP 5.6 < 7.1.25 use list($key, $val) = explode(...)
    return array($key => $val);
}, $data);

Then, you can pull out all of the country Id's like so:

$countries = array_column($groupedData, 'country');

Here is a live demo.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.