Reordering and grouping existing array - php

I have a JSON array as formatted below, generated in PHP using a foreach loop to generate an array from an WP ACF group (see below). I seem to be unable to use GROUP BY when getting the particular fields for this ACF group, hence the double entry for name (with different times) as shown.
[
{"name":"Location1","gigs":
{"start":"16:30","end":"21:15","title":"TestTitle1","class":"fri"}
},
{"name":"Location 2","gigs":
{"start":"15:00","end":"19:00","title":"TestTitle2","class":"fri"}
},
{"name":"Location 1","gigs":
{"start":"21:00","end":"22:00","title":"TestTitle3","class":"fri"}
}
]
This JSON array should ideally be formatted as follows, the difference being the entries with the same name/location should be combined as shown below.
[
{
"name":"Location1",
"gigs": [
{"start":"16:30","end":"21:15","title":"TestTitle1","class":"fri"},
{"start":"21:00","end":"22:00","title":"TestTitle3","class":"fri"}
]
},
{
"name":"Location 2",
"gigs": [
{"start":"15:00","end":"19:00","title":"TestTitle2","class":"fri"}
]
}
]
I've tried several array merge/combine/sort/etc functions available in PHP, but can't get it to output as intended.
Here's the code generating the array/JSON output:
function get_shows( WP_REST_Request $request ) {
$parameters = $request->get_params();
switch($parameters[1]) {
case 'fri':
$show_day = 'fri';
$show_select_day = '20170901';
break;
case 'sat':
$show_day = 'sat';
$show_select_day = '20170902';
break;
case 'sun':
$show_day = 'sun';
$show_select_day = '20170903';
break;
}
$showDates = array();
$args = array(
'posts_per_page' => -1,
'post_type' => 'performances',
'meta_key' => 'per_date',
'meta_value' => $show_select_day
);
$shows = get_posts( $args );
if ( ! empty( $shows ) ) {
$i = 0;
foreach( $shows as $show ) {
$acf = get_fields($show->ID);
$show_loc = get_the_title(get_field('per_location',$show->ID));
$show_title = get_the_title(get_field('per_busker',$show->ID));
if ( ! empty( $acf ) ) {
$showDates[$i]['name'] = $show_loc;
$showDates[$i]['gigs']['start'] = date("H:i", strtotime($acf['per_time_start']));
$showDates[$i]['gigs']['end'] = date("H:i", strtotime($acf['per_time_end']));
$showDates[$i]['gigs']['title'] = $show_title;
$showDates[$i]['gigs']['class'] = $show_day;
}
$i++;
}
}
return $showDates;
}
Any suggestions to get the output in the correct format would be more than welcome. Thanks much!

Try follwong solution. I have change your key Location1 to Location 1 because Location1 != Location 1
$json_data = '[
{"name":"Location 1","gigs":
{"start":"16:30","end":"21:15","title":"TestTitle1","class":"fri"}
},
{"name":"Location 2","gigs":
{"start":"15:00","end":"19:00","title":"TestTitle2","class":"fri"}
},
{"name":"Location 1","gigs":
{"start":"21:00","end":"22:00","title":"TestTitle3","class":"fri"}
}
]';
$arr = json_decode($json_data,true);
$new_array = array();
foreach ($arr as $key => $value) {
if(isset($new_array[$value['name']]))
$new_array[$value['name']]['gigs'][] = $value['gigs'];
else{
$new_array[$value['name']]['name'] = $value['name'];
$new_array[$value['name']]['gigs'][] = $value['gigs'];
}
}
$new_array = array_values($new_array); //to remove keys
echo json_encode($new_array);
DEMO

Related

find array value in array column

i have array like this
$data = array(
array('name'=>'Matemathic','SKS'=>5),
array('name'=>'History','SKS'=>2),
array('name'=>'English','SKS'=>3)
);
i want to search where name 'History' and get SKS value
<?php
$data = array(
array('name'=>'Matemathic','SKS'=>5),
array('name'=>'History','SKS'=>2),
array('name'=>'English','SKS'=>3)
);
foreach($data as $i) {
if ($i['name'] == 'History') {
echo $i['SKS'];
break;
}
}

count how many duplicate keys are in array of objects?

[
{
"playerId":3207,
"playerName":"RyanGarbutt",
"playerPos":"C",
"playerApiId":"5079"
},
{
"playerId":3238,
"playerName":"Max Domi",
"playerPos":"C",
"playerApiId":"5412"
},
{
"playerId":3240,
"playerName":"AnthonyDuclair",
"playerPos":"LW",
"playerApiId":"5441"
}
]
1-> I want to count playerPos(C,LW) occurrences?
2-> How to get data in format like[{"c":"2"},{"LW":"1"}]
You can use array_reduce
$arr = '[{"playerId":3207,"playerName":"RyanGarbutt","playerPos":"C","playerApiId":"5079"},{"playerId":3238,"playerName":"Max Domi","playerPos":"C","playerApiId":"5412"},{"playerId":3240,"playerName":"AnthonyDuclair","playerPos":"LW","playerApiId":"5441"}]';
$arr = json_decode( $arr, true );
$result = array_reduce( $arr , function( $c, $v ) {
isset( $c[ $v[ "playerPos" ] ] ) ? $c[ $v[ "playerPos" ] ]++ : $c[ $v[ "playerPos" ] ] = 1;
return $c;
}, array() );
echo "<pre>";
print_r( $result );
echo "</pre>";
This will result to:
Array
(
[C] => 2
[LW] => 1
)
Doc: http://php.net/manual/en/function.array-reduce.php
Without loop, conditions and callback function.
$arr = '[{"playerId":3207,"playerName":"RyanGarbutt","playerPos":"C","playerApiId":"5079"},{"playerId":3238,"playerName":"Max Domi","playerPos":"C","playerApiId":"5412"},{"playerId":3240,"playerName":"AnthonyDuclair","playerPos":"LW","playerApiId":"5441"}]';
$arr = json_decode( $arr, true );
$result = array_count_values(array_column($arr,"playerPos"));
print_r($result);
Output
Array (
[C] => 2
[LW] => 1
)
Working example
Demo
You can try something like this :
1/ First, create two var you will use as counter of occurences of "C" and "LW" :
$C = 0;
$LW = 0;
2/ Loop through your array with a foreach loop and test each time if the value of your obj for the key "playerPos" is equal to "C" or "LW", then add +1 for your counter var :
foreach($array as $obj) {
$test = $obj['playerPos'];
if ($test == "C")
$C++;
else if ($test == "LW")
$LW++;
}
3/ Then you need to check the value of each var to know the number of occurences.
Is this what you are looking for?
function unique_multidim_array($array, $key) {
$temp_array = array();
$i = 0;
$key_array = array();
foreach($array as $val) {
if (!in_array($val[$key], $key_array)) {
$key_array[$i] = $val[$key];
$temp_array[$i] = $val;
}
$i++;
}
return $temp_array;
}
$data =
'[{
"playerId":3207,"playerName":"RyanGarbutt","playerPos":"C","playerApiId":"5079"},{
"playerId":3238,"playerName":"Max Domi","playerPos":"C","playerApiId":"5412"},{
"playerId":3240,"playerName":"AnthonyDuclair","playerPos":"LW","playerApiId":"5441"}]';
$data=json_decode($data,true);
$uniqueArray = unique_multidim_array($data,'playerPos');
print_r($uniqueArray);
print_r(count($uniqueArray));

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

Encode nested JSON array in php

I want to send nested JSON array.Which contain following format.
${"posts":[{
"abc":"123",
"xyz":"123",
"pro":[{
"name":"Brinjal",
"qty":"500 gms"
},
{
"name":"Brinjal",
"qty":"500 gms"
}]
}]
}
Here is my php code:
$rows = $stmt->fetchAll();
if ($rows) {
$order["posts"] = array();
foreach ($rows as $row) {
$post = array();
$post["order_id"] = $row["order_id"];
$post["order_totalamount"] = $row["order_totalamount"];
$post["address"] = $row["address"];
$post["pincode"] = $row["pincode"];
$post["delivery_timeslot"] = $row["delivery_timeslot"];
$post["order_date"] = $row["order_date"];
$query1= "query";
$rows1 = $stmt->fetchAll();
if ($rows1) {
foreach ($rows1 as $row1) {
$query2= "query";
$rows2 = $stmt->fetchAll();
$post["product"] = array();
if ($rows2) {
$products = array();
foreach ($rows2 as $row2) {
$products["product_name"]=$row2["product_name"];
$products["prod_qty"] = $row2["product_minquantity"];
}
array_push($post["product"],$products);
echo json_encode($products);
}
}
}
array_push($order["posts"], $post);
}
echo json_encode($order);
}
From above code I got result:
$ {"posts":
[{
"order_id":"18",
"order_totalamount":"40",
"address":"2, Chetan Society, Vadodara",
"pincode":"390023",
"delivery_timeslot":"Zone wise delivery",
"order_date":"2016-03-18 17:50:53",
"product":[{"product_name":"Brinjal","prod_qty":"500 gms"}]
}]
}
But my actual product array is:
${"product_name":"Banana","prod_qty":"1 Kg"}{"product_name":"Brinjal","prod_qty":"500 gms"}
Kindly help out. I am stuck on it. tried a lot but did not get success.
In
foreach ($rows2 as $row2) {
$products["product_name"]=$row2["product_name"];
$products["prod_qty"] = $row2["product_minquantity"];
}
You overwrite $products["product_name"]and $products["prod_qty"] with the values of the last $row2.
The line {"product_name":"Banana","prod_qty":"1 Kg"}{"product_name":"Brinjal","prod_qty":"500 gms"} actually consists of two echo's:
{"product_name":"Banana","prod_qty":"1 Kg"}
{"product_name":"Brinjal","prod_qty":"500 gms"}
But you don't see the difference. I suggest echoing a string in-between them or use something like var_dump() to see how many values you're echoing.
You should do something like:
for ($i = 0; $i < count($rows2); $i++) {
$products[$i]["product_name"]=$rows2[$i]["product_name"];
$products[$i]["prod_qty"] = $rows2[$i]["product_minquantity"];
}
This will result in: [{"product_name":"Banana","prod_qty":"1 Kg"},{"product_name":"Brinjal","prod_qty":"500 gms"}]
FYI $array[] = has the same rsults as array_push(), but had less overhead of calling array_push().
EDIT:
Below a complete example since it doesn't seem to workout for you:
//Demo $order
$order = array (
'posts' =>
array (
0 =>
array (
'order_id' => '18',
'order_totalamount' => '40',
'address' => '2, Chetan Society, Vadodara',
'pincode' => '390023',
'delivery_timeslot' => 'Zone wise delivery',
'order_date' => '2016-03-18 17:50:53',
),
),
);
//Demo $rows2
$rows2 = array(
array(
'product_name' => 'banana',
'product_minquantity' => '1 Kg'
),
array(
'product_name' => 'Brinjal',
'product_minquantity' => '500 gms'
)
);
$post['product'] = array();
if ($rows2) {
$products = array();
for ($i = 0; $i < count($rows2); $i++) {
$products[$i]['product_name'] = $rows2[$i]['product_name'];
$products[$i]['prod_qty'] = $rows2[$i]['product_minquantity'];
}
$post['product'] = $products;
echo json_encode($products); //[{"product_name":"banana","prod_qty":"1 Kg"},{"product_name":"Brinjal","prod_qty":"500 gms"}]
}
//$order['posts'][] = $post;
$order['posts'][0] = $order['posts'][0] + $post;
//In this example I only have 1 item in $order['posts'] so I know to add to key 0.
//In your case you need to know which key of $rows1 you need to do the adding.
//Change the foreach loop of $rows to a for loop as well so you can define your own keynames ($i).
echo '<br>==================================================================<br>';
echo json_encode($order);
/*
{
"posts":[
{
"order_id":"18",
"order_totalamount":"40",
"address":"2, Chetan Society, Vadodara",
"pincode":"390023",
"delivery_timeslot":"Zone wise delivery",
"order_date":"2016-03-18 17:50:53",
"product":[
{
"product_name":"banana",
"prod_qty":"1 Kg"
},
{
"product_name":"Brinjal",
"prod_qty":"500 gms"
}
]
}
]
}
*/

Create multidimensional array from keys

Is there a way to create dynamicaly multidimensional array? I have stored in database "path" for each field=>value like that:
field_name : [slideshow][slide][0][title]
field_value : my title
field_name : [slideshow][slide][0][desc]
field_value : my desc
field_name : [slideshow][slide][1][title]
field value : my other title
field_name : [slideshow][slide][1][desc]
field value : my other desc
field_name : [slideshow][settings][duration]
field value : 300
and now I'm trying to figure out how to make it an array again. Obviously there can be lots of fields and complexity so I wanted to avoid some recursions if possible, cause I'm not sure how it will impact performance.
I was playing around with variable variables and trying something like:
$array_name = 'arr';
${$array_name}[slideshow][slide][1][title] = $field->field_value;
print_r($arr);
but this works only if its literally that, and nothing like this works:
${$array_name}.$field->field_name = $field->field_value;
I basically need to store every field as individual row (e.g. for searches in those fields), values can be diffrent types (even serialized arrays), and contain html.
Any advice appreciate.
The basic idea is to split up your field_name string and loop over the parts backward to build up the array. Some recursion is used to merge the arrays, though any performance impact should be negligible.
Example:
// Set up sample data.
$field = new stdClass();
$field->field_name = '[slideshow][slide][0][title]';
$field->field_value = 'my title';
$fields[] = $field;
$field = new stdClass();
$field->field_name = '[slideshow][slide][0][desc]';
$field->field_value = 'my desc';
$fields[] = $field;
$field = new stdClass();
$field->field_name = '[slideshow][slide][1][title]';
$field->field_value = 'my other title';
$fields[] = $field;
$field = new stdClass();
$field->field_name = '[slideshow][slide][1][desc]';
$field->field_value = 'my other desc';
$fields[] = $field;
$field = new stdClass();
$field->field_name = '[slideshow][settings][duration]';
$field->field_value = '300';
$fields[] = $field;
// End sample data.
// array_merge_recursive() doesn't do what we want with numeric keys, so use this
function merge($base, $array) {
foreach ($array as $key => $value) {
if (isset($base[$key]) && is_array($base[$key]) && is_array($value)) {
$base[$key] = merge($base[$key], $value);
} else {
$base[$key] = $value;
}
}
return $base;
}
$result = [];
foreach ($fields as $field) {
$parts = array_reverse(explode('][', trim($field->field_name, '[]')));
$value = $field->field_value;
foreach ($parts as $part) {
$value = [$part => $value];
}
$result = merge($result, $value);
}
print_r($result);
Output:
Array
(
[slideshow] => Array
(
[slide] => Array
(
[0] => Array
(
[title] => my title
[desc] => my desc
)
[1] => Array
(
[title] => my other title
[desc] => my other desc
)
)
[settings] => Array
(
[duration] => 300
)
)
)
You could try something like this.
$cars = array
(
array("Volvo",22,18),
array("BMW",15,13),
array("Saab",5,2),
array("Land Rover",17,15)
);
<?php
echo $cars[0][0].": In stock: ".$cars[0][1].", sold: ".$cars[0][2].".<br>";
echo $cars[1][0].": In stock: ".$cars[1][1].", sold: ".$cars[1][2].".<br>";
echo $cars[2][0].": In stock: ".$cars[2][1].", sold: ".$cars[2][2].".<br>";
echo $cars[3][0].": In stock: ".$cars[3][1].", sold: ".$cars[3][2].".<br>";
?>
<?php
for ($row = 0; $row < 4; $row++) {
echo "<p><b>Row number $row</b></p>";
echo "<ul>";
for ($col = 0; $col < 3; $col++) {
echo "<li>".$cars[$row][$col]."</li>";
}
echo "</ul>";
}
?>

Categories