How to separate a php array items by prefix - php

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

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

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;
}
}

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

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);

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 );
?>

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.

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

Related

PHP - Compare array and output found values [duplicate]

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
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
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;
}
}
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
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);
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 );
?>
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.
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

PHP array filter by pre text from value

I have an array like below
Array
(
[0] => country-indonesia
[1] => country-myanmar
[2] => access-is_airport
[3] => heritage-is_seagypsy
)
From that array I want to make separate array only for [country] ,[access], [heritage]
So for that I have to check array value by text before '-'. I am not sure how to do it. so i can't apply code here. I just have the array in PHP
A modified answer, if you want to get the specific types only.
<?php
$arr = [
'country-indonesia',
'country-myanmar',
'access-is_airport',
'heritage-is_seagypsy',
];
$new_array = [];
$types = ['country', 'heritage', 'access'];
foreach ($arr as $element) {
$fac = explode('-', $element);
foreach ($types as $type) {
if ($fac[0] === $type) {
$new_array[$type][] = $fac[1];
}
}
}
$country = $new_array['country'];
$access = $new_array['access'];
$heritage = $new_array['heritage'];
var_dump($new_array);
A simple and easy solution in 3 lines of code using array_walk
<?php
$arr = [
'country-indonesia',
'country-myanmar',
'access-is_airport',
'heritage-is_seagypsy',
];
$new_array = [];
array_walk($arr, function($item) use (&$new_array){
//if(false === strpos($item, '-')) return;
list($key,$value) = explode('-', $item, 2);
$new_array[$key][] = $value;
});
print_r($new_array);
Gives this output:
Array
(
[country] => Array
(
[0] => indonesia
[1] => myanmar
)
[access] => Array
(
[0] => is_airport
)
[heritage] => Array
(
[0] => is_seagypsy
)
)
If you don't want empty and duplicate entries:
<?php
$arr = [
'country-indonesia',
'country-myanmar',
'access-is_airport',
'heritage-is_seagypsy',
];
$new_array = [];
array_walk($arr, function($item) use (&$new_array){
if(false === strpos($item, '-')) return;
list($key,$value) = explode('-', $item, 2);
if(empty($value) || array_key_exists($key, $new_array) && in_array($value, $new_array[$key])) return;
$new_array[$key][] = $value;
});
print_r($new_array);
you can do it by using explode and in_array functions
<?php
$arr = ["country-indonesia","country-myanmar","access-is_airport","heritage-is_seagypsy"];
$newArr = array();
foreach($arr as $k=> $val){
$valArr = explode("-", $val);
if(!in_array($valArr[0], $newArr)){
$newArr[] = $valArr[0];
}
}
print_r($newArr);
?>
live demo
You need PHP's strpos() function.
Just loop through every element of the array and try something like:
if( strpos($array[$i], "heritage") != false )
{
// Found heritage, do something with it
}
(Rough example written from my cellphone while feeding baby, may have typos but it's the basics of what you need)
Read further here: http://php.net/manual/en/function.strpos.php
//first lets set a variable equal to our array for ease in working with i.e
// also create a new empty array to hold our filtered values
$countryArray = array();
$accessArray = array();
$heritageArray = array();
$oldArray = Array(country-indonesia, country-myanmar, access-is_airport, heritage-is_seagypsy);
//Next loop through our array i.e
for($x = 0; $x < count($oldArray); $x++){
// now filter through the array contents
$currentValue = $oldArray[$x];
// check whether the current index has any of the strings in it [country] ,[access], [heritage] using the method : strpos()
if(strpos($currentValue,'country')){
//if this particular value contains the keyword push it into our new country array //using the array_push() function.
array_push($countryArray,$currentValue);
}elseif(strpos($currentValue,'access')){
// else check for the access string in our current value
// once it's found the current value will be pushed to the $accessArray
array_push($accessArray,$currentValue);
}elseif(strpos($currentValue,'heritage')){
// check for the last string value i.e access. If found this too should be pushed to //the new heritage array i.e
array_push($heritageArray,$currentValue);
}else{
// do nothing
}
}
//I believe that should work: cheers hope

getting foreach $key and store into difference variable

$Ascore = 30
$Bscore = 30
$Cscore = 20
$Dscore = 20
$data = array(
'A1' => $Ascore,
'B1' => $Bscore,
'C1' => $Cscore,
'D1' => $Dscore
);
$highest = max($data);
foreach($data as $key => $value){
if($value === $highest){
echo $key;
//echo output (t1,t3);
}
something like this
getting them store in different variables
$type1 = $key[0]; //this will be t1//
$type2 = $key[1]; //this will be t3//
My intention is to somehow make the element I found at $key and put them into different variable , how I'm going to achieve that? As I have the idea but I cant get it work on.
Assuming I'm reading the question correctly, because it is a bit vague:
$data = [1,3,5,3,5];
$highest = max($data);
$result = array_keys(
array_filter(
$data,
function($value) use ($highest) {
return $value == $highest;
}
)
);
var_dump($result);
Do you mean store the keys where the corresponding value is the maximum value in the array? If so try:
$highest = max($data);
$max_keys = array();
foreach($data as $key => $value){
if ($value === $highest){
array_push($max_keys, $key);
}
}
If you must have the keys in separate variables just add:
list($type1, $type2) = $max_keys;

php - create assciative array while loop

I am trying to create 2 new arrays out of one existing array ($array), using the following "foreach" loop. However I am not sure it is correct:
$emails = array();
$numbers = array();
while($array){
$entry = $array['entry1'];
$number = number($entry);
if(isset($number) && (strlen($number) > 9)){
$numbers[] = array('entry1' => $entry, 'number' => $number);
}
else{
$email = email($entry);
$emails[] = array('entry1' => $entry, 'email' => $email);
}
}
should the internal arrays have []?
do I even need to start the arrays outside of the while loop? or skip it?
is it better to use a foreach loop?
Update:
Okay, here is the original array: It is extracted from a mysql query, of sets of two numbers:
{('uid1','uid2'),('uid1','uid5'),('uid9','uid93'),....)
There might be other data in each row, but these are the only two data points that really matter.
What I am trying to do is for a specific user ($entry), create two separate arrays: of all the users that have numbers (that's a function we have), and all the rest - of their emails.
So the outcome will be 2 new arrays which will look like this:
for a specific uid79887:
numbers array: {('uid8','xxx-xxxx-xxx'),('uid34','yyy-yyyy-yyy'),('uid654','vvv-vvvv-vvv')}
emails array: {('uid4','mmm#mmm.com'),('uid1','lll#lll.com'),('uid55554','ppp#ppp.com')}
Few things first:
It's good practice to initialize your variables, just do it (it has many positives).
What kind of test is while($array)? You should use foreach( $array as $entry) or while( count( $array)) if you're removing items from array.
Why are you testing isset( $number) when it's always set? It's initialized variable. You're probably checking null, so use !is_null() or ($number !== null). Even if it works it's misleading.
I guess your code should look like this:
$emails = array();
$numbers = array();
foreach( $array as $entry){
$entry = isset( $entry['entry1']) ? $entry['entry1'] : null;
$number = number( $entry);
if( strlen($number) > 9 ){ // If $number is empty it will have strlen < 1 .)
$numbers[] = array('entry1' => $entry, 'number' => $number);
} else {
$emails[] = array('entry1' => $entry, 'email' => email( $entry));
}
}
I guess this is what you are trying to acheive:
$emails = $numbers = Array();
foreach($array as $item) {
$e = $item['entry1'];
$number = number($e);
if(strlen($number) > 9) {
$numbers[] = Array('entry1' => $e, 'number' => $number);
}
else {
$email = email($entry);
$emails[] = Array('entry1' => $e, 'email' => $email);
}
}
in your code, while($array) do not loop on the array, it loop until $array == false
as $array do not change in your loop it will either never enter or the loop, or never exit
generally, using a foreach loop produce code easier to understand
Assuming this isn't some kind of homework assignment, why don't you do it this way:
$emails = array();
$numbers = array();
foreach( $array as $entry )
{
$number = number($entry);
if( $number && strlen($number) > 9 )
{
array_push($numbers, array('entry1' => $entry, 'number' => $number));
}
else
{
array_push($emails, array('entry1' => $entry, 'email' => email($entry)));
}
}
It is better to use built in functions that trying to roll your own. The foreach() function works very well.

php array keys problem

I have the following code:
$rt1 = array
(
'some_value1' => 'xyz1',
'some_value2' => 'xyz2',
'value_1#30'=>array('0'=>1),
'value_2#30'=>array('0'=>2),
'value_3#30'=>array('0'=>3),
'value_1#31'=>array('0'=>4),
'value_2#31'=>array('0'=>5),
'value_3#31'=>array('0'=>6),
'some_value3' => 'xyz3',
'some_value4' => 'xyz4',
);
$array_30 = array
(
'0'=>1,
1=>'2',
2=>'3'
);
$array_31 = array
(
'0'=>4,
'1'=>'5',
'2'=>'6'
);
I need to make it an array and insert the array_30 and array_31 into a DB.
foreach($rt1 as $value){
$rt2[] = $value['0'];
}
The question was updated, so here is an updated answer. Quick check, you should really try and update this to whatever more generic purpose you have, but as a proof of concept, a runnable example:
<?php
$rt1 = array
(
'some_value1' => 'xyz1',
'some_value2' => 'xyz2',
'value_1#30'=>array('0'=>1),
'value_2#30'=>array('0'=>2),
'value_3#30'=>array('0'=>3),
'value_1#31'=>array('0'=>4),
'value_2#31'=>array('0'=>5),
'value_3#31'=>array('0'=>6),
'some_value3' => 'xyz3',
'some_value4' => 'xyz4',
);
$finalArrays = array();
foreach($rt1 as $key=>$value){
if(is_array($value)){
$array_name = "array_".substr($key,-2);
${$array_name}[] = $value['0'];
}
}
var_dump($array_30);
var_dump($array_31);
?>
will output the two arrays with the numbers 1,2,3 and 4,5,6 respectivily
i assume you want to join the values of each of the second-level arrays, in which case:
$result = array();
foreach ($rt1 as $arr) {
foreach ($arr as $item) {
$result[] = $item;
}
}
Inspired by Nanne (which reminded me of dynamically naming variables), this solution will work with every identifier after the \#, regardless of its length:
foreach ( $rt1 as $key => $value )
{
if ( false == strpos($key, '#') ) // skip keys without #
{
continue;
}
// the part after the # is our identity
list(,$identity) = explode('#', $key);
${'array_'.$identity}[] = $rt1[$key]['0'];
}
Presuming that this is your actual code, probably you will need to copy the array somewhere using foreach and afterwards create the new array as you wish:
foreach($arr as $key => $value) {
$arr[$key] = 1;
}

Categories