Separate multidimensional array into separate arrays - php

I am trying to get my head around arrays.
The arrays should look like this:
$questions[$a] => array( [0] => No, comment1
[1] => Yes, comment2
[2] => No, comment3 )
$answer[$a] => array( [0] => No
[1] => Yes
[3] => No )
$comment[$a] => array( [0] => comment1
[1] => comment2
[3] => comment3 )
=========================================================================
SECOND EDIT: Need to execute this in the loop to create a third array -
if($answer[$a] == "Yes") { $display[$a] = "style='display:none'";
} else { $display[$a] = "style='display:block'"; }
This is what i have: (28th for minitech)
while ($a > $count)
{
if($count > 11) {
foreach($questions as $q) {
list($answer, $comments[]) = explode(',', $q);
if($answer === "Yes") {
$display[$a] = "style='display:none'";
} else {
$display[$a] = "style='display:block'";
}
$answers[] = $answer;
}
}
$a++;
}

If they are actually strings, explode works:
$answers = array();
$comments = array();
$display = array();
foreach(array_slice($questions, 11) as $question) {
list($answer, $comments[]) = explode(',', $question);
$display[] = $answer === 'Yes' ? 'style="display: none"' : 'style="display: block"';
$answers[] = $answer;
}
Here’s a demo!

Change your while loop to this
while ...
{
$parts = explode(',', $questions[$a]);
$answer[$a][] = trim($parts[0]);
$comment[$a][] = trim($parts[1]);
}
In your original code you were overwriting the $answer[$a] and $comment[$a] each time, not appending to the end of an array

$questions[$a] = array('Q1?' => 'A1', 'Q2?' => 'A2', 'Q3?' => 'A3');
foreach($questions[$a] as $key => $value)
{
$comment[$a][] = $key;
$answer[$a][] = $value;
}

This should work.
foreach ($questions[$a] as $key=>$value){
$temp = explode(',',$value);
$answer[$key] = $temp[0];
$comment[$key] = $temp[1];
}
$key will have 0,1,2 respectively. $value will have the values for each $question[$a](No,Comment1 ....)

Can't think of a funky one-liner, but this should do it:
foreach ($questions as $a => $entries) {
foreach ($entries as $k => $entry) {
$parts = array_map('trim', explode(',', $entry));
$answer[$a][$k] = $parts[0];
$comment[$a][$k] = $parts[1];
}
}

$questions = array( 0 => 'No,comment1',1 => 'Yes,comment2',2 => 'No,comment3' );
foreach($questions as $question)
{
$parts = explode(",",$question);
$answer[] = $parts[0];
$comment[] = $parts[1];
}
echo "<pre>";
print_r($answer);
print_r($comment);

Here is the right answer
foreach($questions as $key => $question){
foreach($question as $q => $data){
$data= explode(',',$data);
$comments[$key][$q] = $data[0];
$answer[$key][$q] = $data[1];
}
}

If the values in $questions are comma-separated strings you could use an array_walk function to populate your $answer and $comment arrays
$question = array(...); //array storing values as described
$answer = array();
$comment = array();
array_walk($question, function ($value, $key) use ($answer,$comment) {
$value_array = explode(',', $value);
$answer[$key] = $value_array[0];
$comment[$key] = $value_array[1];
});
Note that this is shown using an anonymous function (closure) which requires PHP >= 5.3.0. If you had a lower version of PHP, you would need to declare a named function, and declare $answer and $comment as globals in the function. I think this is a hacky approach (using globals like this) so if I was using PHP < 5.3 I would probably just use a foreach loop like other answers to your question propose.
Functions like array_walk, array_filter and similar functions where callbacks are used are often great places to leverage the flexibility provided by anonymous functions.

Related

How to separate a php array items by prefix

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

Creating a dynamic hierarchical array in PHP

I have this general data structure:
$levels = array('country', 'state', 'city', 'location');
I have data that looks like this:
$locations = array(
1 => array('country'=>'USA', 'state'=>'New York', 'city'=>'NYC', 'location'=>'Central Park', 'count'=>123),
2 => array('country'=>'Germany', ... )
);
I want to create hierarchical arrays such as
$hierarchy = array(
'USA' => array(
'New York' => array(
'NYC' => array(
'Central Park' => 123,
),
),
),
'Germany' => array(...),
);
Generally I would just create it like this:
$final = array();
foreach ($locations as $L) {
$final[$L['country']][$L['state']][$L['city']][$L['location']] = $L['count'];
}
However, it turns out that the initial array $levels is dynamic and can change in values and length So I cannot hard-code the levels into that last line, and I do not know how many elements there are. So the $levels array might look like this:
$levels = array('country', 'state');
Or
$levels = array('country', 'state', 'location');
The values will always exist in the data to be processed, but there might be more elements in the processed data than in the levels array. I want the final array to only contain the values that are in the $levels array, no matter what additional values are in the original data.
How can I use the array $levels as a guidance to dynamically create the $final array?
I thought I could just build the string $final[$L['country']][$L['state']][$L['city']][$L['location']] with implode() and then run eval() on it, but is there are a better way?
Here's my implementation. You can try it out here:
$locations = array(
1 => array('country'=>'USA', 'state'=>'New York', 'city'=>'NYC', 'location'=>'Central Park', 'count'=>123),
2 => array('country'=>'Germany', 'state'=>'Blah', 'city'=>'NY', 'location'=>'Testing', 'count'=>54),
);
$hierarchy = array();
$levels = array_reverse(
array('country', 'state', 'city', 'location')
);
$lastLevel = 'count';
foreach ( $locations as $L )
{
$array = $L[$lastLevel];
foreach ( $levels as $level )
{
$array = array($L[$level] => $array);
}
$hierarchy = array_merge_recursive($hierarchy, $array);
}
print_r($hierarchy);
Cool question. A simple approach:
$output = []; //will hold what you want
foreach($locations as $loc){
$str_to_eval='$output';
for($i=0;$i<count($levels);$i++) $str_to_eval .= "[\$loc[\$levels[$i]]]";
$str_to_eval .= "=\$loc['count'];";
eval($str_to_eval); //will build the array for this location
}
Live demo
If your dataset always in fixed structure, you might just loop it
$data[] = [country=>usa, state=>ny, city=>...]
to
foreach ($data as $row) {
$result[][$row[country]][$row[state]][$row[city]] = ...
}
In case your data is dynamic and the levels of nested array is also dynamic, then the following is an idea:
/* convert from [a, b, c, d, ...] to [a][b][...] = ... */
function nested_array($rows, $level = 1) {
$data = array();
$keys = array_slice(array_keys($rows[0]), 0, $level);
foreach ($rows as $r) {
$ref = &$data[$r[$keys[0]]];
foreach ($keys as $j => $k) {
if ($j) {
$ref = &$ref[$r[$k]];
}
unset($r[$k]);
}
$ref = count($r) > 1 ? $r : reset($r);
}
return $data;
}
try this:
<?php
$locations = [
['country'=>'USA', 'state'=>'New York', 'city'=>'NYC', 'location'=>'Central Park', 'street'=>'7th Ave', 'count'=>123],
['country'=>'USA', 'state'=>'Maryland', 'city'=>'Baltimore', 'location'=>'Harbor', 'count'=>24],
['country'=>'USA', 'state'=>'Michigan', 'city'=>'Lansing', 'location'=>'Midtown', 'building'=>'H2B', 'count'=>7],
['country'=>'France', 'state'=>'Sud', 'city'=>'Marseille', 'location'=>'Centre Ville', 'count'=>12],
];
$nk = array();
foreach($locations as $l) {
$jsonstr = json_encode($l);
preg_match_all('/"[a-z]+?":/',$jsonstr,$e);
$narr = array();
foreach($e[0] as $k => $v) {
if($k == 0 ) {
$narr[] = '';
} else {
$narr[] = ":{";
}
}
$narr[count($e[0]) -1] = ":" ;
$narr[] = "";
$e[0][] = ",";
$jsonstr = str_replace($e[0],$narr,$jsonstr).str_repeat("}",count($narr)-3);
$nk [] = $ko =json_decode($jsonstr,TRUE);
}
print_r($nk);
Database have three field:
here Name conatin contry state and city name
id,name,parentid
Pass the contry result to array to below function:
$data['contry']=$this->db->get('contry')->result_array();
$return['result']=$this->ordered_menu( $data['contry'],0);
echo "<pre>";
print_r ($return['result']);
echo "</pre>";
Create Function as below:
function ordered_menu($array,$parent_id = 0)
{
$temp_array = array();
foreach($array as $element)
{
if($element['parent_id']==$parent_id)
{
$element['subs'] = $this->ordered_menu($array,$element['id']);
$temp_array[] = $element;
}
}
return $temp_array;
}

Create chain of keys from string

Suppose, i have the fallowing json:
{
"foo.bar": 1
}
and i want to save this like this:
$array["foo"]["bar"] = 1
but i also can have more than 2 "parameters" in string. For example:
{
"foo.bar.another_foo.another_bar": 1
}
and i want to save this same way.
$array["foo"]["bar"]["another_foo"]["another_bar"] = 1
Any ideas how can i do that in case that i don't know how many parameters i have?
This is far from the nicest solution, but I've been programming all day so I'm a little tired, but I hope it gives you something to work off, or at least a working solution for the time being.
Here's the IDEone of it working: click
And here's the code:
$json = '{
"foo.bar": 1
}';
$decoded = json_decode($json, true);
$data = array();
foreach ($decoded as $key => $value) {
$keys = explode('.', $key);
$data[] = buildNestedArray($keys, $value);
}
print_r($data);
function buildNestedArray($keys, $value) {
$new = array();
foreach ($keys as $key) {
if (empty($new)) {
$new[$key] = $value;
} else {
array_walk_recursive($new, function(&$item) use ($key, $value) {
if ($item === $value) {
$item = array($key => $value);
}
});
}
}
return $new;
}
Output:
Array
(
[0] => Array
(
[foo] => Array
(
[bar] => 1
)
)
)
Wasn't sure whether your JSON string could have multiples or not so I made it handle the former.
Hope it helps, may come back and clean it up a bit in the future.
Start with a json_decode
Then build a foreach loop to break apart the keys and pass them to some kind of recursive function that creates the values.
$old_stuff = json_decode($json_string);
$new_stuff = array();
foreach ($old_stuff AS $key => $value)
{
$parts = explode('.', $key);
create_parts($new_stuff, $parts, $value);
}
Then write your recursive function:
function create_parts(&$new_stuff, $parts, $value)
{
$part = array_shift($parts);
if (!array_key_exists($part, $new_stuff)
{
$new_stuff[$part] = array();
}
if (!empty($parts)
{
create_parts($new_stuff[$part], $parts, $value);
}
else
{
$new_stuff = $value;
}
}
I have not tested this code so don't expect to just cut and past but the strategy should work. Notice that $new_stuff is passed by reference to the recursive function. This is very important.
Try the following trick for "reformatting" into json string which will fit the expected array structure:
$json = '{
"foo.bar.another_foo.another_bar": 1
}';
$decoded = json_decode($json, TRUE);
$new_json = "{";
$key = key($decoded);
$keys = explode('.', $key);
$final_value = $decoded[$key];
$len = count($keys);
foreach ($keys as $k => $v) {
if ($k == 0) {
$new_json .= "\"$v\"";
} else {
$new_json .= ":{\"$v\"";
}
if ($k == $len - 1) $new_json .= ":$final_value";
}
$new_json .= str_repeat("}", $len);
var_dump($new_json); // '{"foo":{"bar":{"another_foo":{"another_bar":1}}}}'
$new_arr = json_decode($new_json, true);
var_dump($new_arr);
// the output:
array (size=1)
'foo' =>
array (size=1)
'bar' =>
array (size=1)
'another_foo' =>
array (size=1)
'another_bar' => int 1

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;

Add data dynamically to an Array

I want to add data to an array dynamically. How can I do that? Example
$arr1 = [
'aaa',
'bbb',
'ccc',
];
// How can I now add another value?
$arr2 = [
'A' => 'aaa',
'B' => 'bbb',
'C' => 'ccc',
];
// How can I now add a D?
There are quite a few ways to work with dynamic arrays in PHP.
Initialise an array:
$array = array();
Add to an array:
$array[] = "item"; // for your $arr1
$array[$key] = "item"; // for your $arr2
array_push($array, "item", "another item");
Remove from an array:
$item = array_pop($array);
$item = array_shift($array);
unset($array[$key]);
There are plenty more ways, these are just some examples.
$array[] = 'Hi';
pushes on top of the array.
$array['Hi'] = 'FooBar';
sets a specific index.
Let's say you have defined an empty array:
$myArr = array();
If you want to simply add an element, e.g. 'New Element to Array', write
$myArr[] = 'New Element to Array';
if you are calling the data from the database, below code will work fine
$sql = "SELECT $element FROM $table";
$query = mysql_query($sql);
if(mysql_num_rows($query) > 0)//if it finds any row
{
while($result = mysql_fetch_object($query))
{
//adding data to the array
$myArr[] = $result->$element;
}
}
You should use method array_push to add value or array to array exists
$stack = array("orange", "banana");
array_push($stack, "apple", "raspberry");
print_r($stack);
/** GENERATED OUTPUT
Array
(
[0] => orange
[1] => banana
[2] => apple
[3] => raspberry
)
*/
Like this?:
$array[] = 'newItem';
In additon to directly accessing the array, there is also
array_push — Push one or more elements onto the end of array
$dynamicarray = array();
for($i=0;$i<10;$i++)
{
$dynamicarray[$i]=$i;
}
Adding array elements dynamically to an Array And adding new element
to an Array
$samplearr=array();
$count = 0;
foreach ($rslt as $row) {
$arr['feeds'][$count]['feed_id'] = $row->feed_id;
$arr['feeds'][$count]['feed_title'] = $row->feed_title;
$arr['feeds'][$count]['feed_url'] = $row->feed_url;
$arr['feeds'][$count]['cat_name'] = $this->get_catlist_details($row->feed_id);
foreach ($newelt as $cat) {
array_push($samplearr, $cat);
}
++$count;
}
$arr['categories'] = array_unique($samplearr); //,SORT_STRING
$response = array("status"=>"success","response"=>"Categories exists","result"=>$arr);
just for fun...
$array_a = array('0'=>'foo', '1'=>'bar');
$array_b = array('foo'=>'0', 'bar'=>'1');
$array_c = array_merge($array_a,$array_b);
$i = 0; $j = 0;
foreach ($array_c as $key => $value) {
if (is_numeric($key)) {$array_d[$i] = $value; $i++;}
if (is_numeric($value)) {$array_e[$j] = $key; $j++;}
}
print_r($array_d);
print_r($array_e);
Fastest way I think
$newArray = array();
for($count == 0;$row = mysql_fetch_assoc($getResults);$count++)
{
foreach($row as $key => $value)
{
$newArray[$count]{$key} = $row[$key];
}
}

Categories