PHP foreach + continue not working on multidimensional array - php

I'm looking for a way to filter the array on a foreach loop based on two parameters..
I have in my output the following array:
[
{
"entry_id": "1",
"title": "something",
"grades": [
"3",
"4",
"5",
"6"
],
"subject": [
"science"
]
},
{
"entry_id": "2",
"title": "something else",
"grades": [
"7",
"8",
"9",
"10"
],
"subject": [
"math"
]
},
]
I'm trying to return only entry_id 2 using foreach + break, from what I've read it seems like this should work..
$subject = 'math';
$grade = '10';
foreach ( $results as $key => &$result ) {
if($subject && !in_array($subject, $result['subject'])){
break;
}
if($grade && !in_array($grade, $result['grades'])){
break;
}
}
But it's returning all entries..

After searching some more seems like unset + array_values will do what I need:
foreach ( $results as $key => &$result ) {
if($subject && !in_array($subject, $result['subject'])){
unset($results[$key]);
$results = array_values($results);
}
if($grade && !in_array($grade, $result['grades'])){
unset($results[$key]);
$results = array_values($results);
}
}

It seems like you need to add the current entry to a new array when it passes any of the tests. So change the !in_array() test to in_array(), and add to the result inside that if block.
$realresults = array();
foreach ( $results as $key => &$result ) {
if($subject && in_array($subject, $result['subject'])){
$realresults[] = $result;
} elseif($grade && in_array($grade, $result['grades'])){
$realresults[] = $result;
}
}

Related

Convert JSON IN LARAVEL

Here is my JSON
[
{
"TIMESTAMP": "2021-06-09 13:13:26",
"COL1": "10",
"COL2": "20",
"COL3": "30"
},
{
"TIMESTAMP": "2021-06-22 13:13:26",
"COL1": "20",
"COL2": "30",
"COL3": "40"
},
{
"TIMESTAMP": "2021-06-21 13:13:26",
"COL1": "1",
"COL2": "2",
"COL3": "3"
},
{
"TIMESTAMP": "2021-06-20 13:13:26",
"COL1": "40",
"COL2": "50",
"COL3": "60"
}
]
I need to refactor the json According to the Column name like (EXPECTED OUTPUT)
[
{
"TITLE":"COL1"
"DATA":[10,20,1,40]
},
{
"TITLE":"COL2"
"DATA":[20,30,2,50]
},
{
"TITLE":"COL3"
"DATA":[30,40,3,60]
},
]
I was tried but it not working
$data = json_decode($result, true);
$refactored = array_map(function($item) {
return (object)[
'TIMESTAMP' => $item['TIMESTAMP'],
'DATA' => [ $item['COL1'], $item['COL2'], $item['COL3'] ]
];
}, $data);
dump($refactored);
Someone help me out with this. The column may be 3 or more and it must be dynamic. Thanks in advance.
You can transform your JSON like this:
$data = json_decode($result, true);
$refactored = array_reduce($json, function($carry, $item) {
foreach($item as $key => $value) {
if (str_starts_with($key, 'COL')) {
$index = substr($key, 3, 1) - 1;
if (!isset($carry[$index])) {
$carry[$index] = [
'Title' => $key
];
}
$carry[$index]['Data'][] = $value;
}
}
return $carry;
}, []);
dump($refactored);
I am always a fan of using the value you want to group your data by as a temporary array key, that makes things easier, and can simply be reset by using array_values afterwards.
$input = json_decode('…', true);
$output = [];
foreach($input as $item) {
foreach($item as $key => $value) {
if($key != 'TIMESTAMP') {
$output[$key]['TITLE'] = $key;
$output[$key]['DATA'][] = (int)$value;
}
}
}
$output = array_values($output);
echo json_encode($output);
All you have to do is re-encode the processed data:
json_encode($refactored) will give you the output that you want.
P.S. you don't have to cast to an object. It works as array as well.

multidimensional array push an objectwise not working properly

I have one array which needs to formatted in specific way but it is generating a random key for one of the object. See my code below
$temp = [
[
"UID" => "100",
"UPID" => "001",
"PID" => "test1"
],
[
"UID" => "1001",
"UPID" => "002",
"PID" => "test1"
]
];
$child = [];
foreach ($temp as $key => $value) {
$child[$value['UID']][$key]['UPID'] = $value['UPID'];
$child[$value['UID']][$key]['PID'] = $value['PID'];
}
$oldParentData['childUserProductDetail'] = $child;
echo "<pre>";
$result = json_encode($oldParentData, true);
print_r($result);
my expected output
{
"childUserProductDetail": {
"100": [
{
"UPID": "001",
"PID": "test1"
}
],
"1001": [
{
"UPID": "002",
"PID": "test1"
}
]
}
}
getting output
{
"childUserProductDetail": {
"100": [
{
"UPID": "001",
"PID": "test1"
}
],
"1001": {
"1": { // See 1 as key here, that is unwanted
"UPID": "002",
"PID": "test1"
}
}
}
}
Here i don't have idea second time array is not creating and 1 coming from where.kindly anyone update my code based on my expected answer.
Just small change. Remove the [Key] section that is creating indexes like 0, 1.
So even for UID = 1001 this is first record, but due to loop the key is at 1 which we need to remove.
foreach ($temp as $key => $value) {
$child[$value['UID']][] = ['UPID' => $value['UPID'], 'PID'=> $value['PID']];
}

Php - creating json object

I am trying to create a json object from the data that I get from Ninja Forms that would look like this:
{
"title": "Contact Me",
"fields": [
{
"label": "Name",
"type": "textbox",
"required": "1"
},
{
"label": "Email",
"type": "email",
"required": "1"
}
]
}
I am trying to do so, like this:
$settings = ['label', 'type', 'required'];
$formTitle = Ninja_Forms()->form( 1 )->get()->get_setting('title');
$formFields = Ninja_Forms()->form(1)->get_fields();
$data = ['title' => $formTitle];
foreach ($formFields as $formField) {
$key = $formField->get_setting('key');
foreach ($settings as $setting) {
$data['fields'][$key][][$setting] = $formField->get_setting($setting);
}
}
return $data;
But, the result of that looks like this:
{
"title": "Contact Me",
"fields": {
"name": [
{ "label": "Name" },
{ "type": "textbox" },
{ "required": "1"}
],
"email": [
{ "label": "Email" },
{ "type": "email" },
{ "required": "1" }
],
How can I do this, so that the result looks like the one I have shown above?
I have also tried like this:
foreach ($settings as $setting) {
$data['fields'][] = $formField->get_setting($setting);
}
But, that gave me this kind of result:
{
"title": "Contact Me",
"fields": [
"Name",
"textbox",
"1",
"Email",
"email",
"1",
"Message",
"textarea",
"1",
"Submit",
"submit",
null
]
}
This gave me the wanted result:
foreach ($formFields as $formField) {
$key = $formField->get_setting('key');
foreach ($settings as $setting) {
$object[$setting] = $formField->get_setting($setting);
}
$data['fields'][] = $object;
}
return $data;
One way to look at this is to count the dimensions of the data. In your desired format, the deepest item is:
{ "fields": [ { "label": "Name"
So you have object -> array -> object.
If we indent each array in your code, we have:
$data // outermost array
['fields']
[$key]
[] // innermost array
[$setting] = $value; // key in innermost array
Or if we were to declare it with just one value:
$data = array(
'field' => array(
$key => array(
0 => array(
$setting => $value
)
)
)
);
So you have 4 levels of array, instead of 3.
Comparing to the JSON, taking an array with numeric keys as "array" and one with non-numeric keys as "object", the pattern is object -> object -> array -> object.
So it's the [$key] we need to eliminate, because it's creating an extra object dimension.
But we don't want to increment the key at [] for each item either, so we need to either make our value in advance...
foreach ($settings as $setting) {
$object[$setting] = $formField->get_setting($setting);
}
$data['fields'][] = $object;
...or choose our key in advance:
$i++;
foreach ($settings as $setting) {
$data['fields'][$i] = $formField->get_setting($setting);
}

Finding a value in php multidimensional array and adding data to that array

I have a multidimensional JSON array that I need to add values to. The JSON array is external and I cannot change its format.
I've tried doing 3 foreach loops, but then I get myself lost in how to add data to the array. I keep catching myself stuck in a loop.
Here's the JSON:
{
"positions": [{
"report_at": "2017-03-13 20:04:10",
"elev": "0",
"dir": "0",
"id": "1"
}, {
"report_at": "2017-03-07 00:28:14",
"elev": "1240",
"dir": "89",
"id": "2"
}]
}
I have unique data I need to add to id 1, and another set of unique data I need to add to id 2.
Here's what I've tried:
$data = json_decode( $result, true );
foreach ( $data as $d ) {
foreach ( $d as $key => $data ) {
if ( $data['id'] == '1' ) {
$data[] = array(
"online_status" => "1",
"name" => "Test User",
);
} elseif ( $data['id'] == '2' ) {
$data[] = array(
"online_status" => "0",
"name" => "Another User",
);
}
}
}
$json = json_encode( $data );
echo $json;
I think once I can get this figured out, then I can pull data from MySQL, build small arrays based off that data, then add those to these sub-arrays where the ID matches the SQL ID. Any help is appreciated.
JSON seems to be just object with "positions" field which is array, you need to modify.
$data = json_decode($json, TRUE);
foreach ($data['positions'] as &$userInfo) {
if ($userInfo['id'] == 1) {
$userInfo['online_status'] = 'offline';
$userInfo['name'] = 'Test user';
}
}
echo json_encode($data);
Notice "&" sign in foreach, which means, that modification made within foreach, will be stored to original array.
Also you should be aware of key=>value naming in foreach. Your second foreach creates variable named $data, which means, that you are loosing pointer to original array!
Use the following approach:
$data = json_decode($result, true);
foreach ($data['positions'] as &$item) {
if ($item['id'] == "1") {
$item = array_merge($item, ["online_status" => "1", "name" => "Test User"]);
} else if ($item['id'] == "2") {
$item = array_merge($item, ["online_status" => "0", "name" => "Another User"]);
}
}
$json = json_encode($data, JSON_PRETTY_PRINT);
echo $json;
The output:
{
"positions": [
{
"report_at": "2017-03-13 20:04:10",
"elev": "0",
"dir": "0",
"id": "1",
"online_status": "1",
"name": "Test User"
},
{
"report_at": "2017-03-07 00:28:14",
"elev": "1240",
"dir": "89",
"id": "2",
"online_status": "0",
"name": "Another User"
}
]
}

Group array objects by properties

How to group array by 'tax'and 'concept' and SUM attribute 'val'?
I looking for create a single object when tax and concept are the same, also SUM the val.
I tried with simple foreach and validation inside, but doesnt work.
thanks.
echo json_encode($array);
Array Print
[
{
"tax": "10",
"concept": "TUC",
"val": "10"
},
{
"tax": "10",
"concept": "TUC",
"val": "86"
},
{
"tax": "15",
"concept": "TUC",
"val": "8"
},
{
"tax": "11",
"concept": "IPS",
"val": "6"
},
{
"tax": "11",
"concept": "IPS",
"val": "45"
}
]
Expected Result
[
{
"tax": "10",
"concept": "TUC",
"val": "96"
},
{
"tax": "15",
"concept": "TUC",
"val": "8"
},
{
"tax": "11",
"concept": "IPS",
"val": "51"
}
]
You can use array_reduce() here. You'll use the tax value as a key you're grouping on, and reduce the array to unique tax elements while simultaneously producing the sum of val values. The only caveat with this approach is that transforming it to JSON will make PHP think that the outer element is an object and not an array (even though it is an array, this is because we end up using non-default array indexing). But, this is easily mitigated with a call to array_values().
$array = // your array from above
$result = array_reduce($array, function($carry, $item) {
if(!isset($carry[$item->tax])) {
$carry[$item->tax] = $item;
} else {
$carry[$item->tax]->val += $item->val;
}
return $carry;
});
$result = array_values($result);
echo json_encode($result);
You can see from this demo that it produces:
[{
"tax": "10",
"concept": "TUC",
"val": 96
}, {
"tax": "15",
"concept": "TUC",
"val": "8"
}, {
"tax": "11",
"concept": "IPS",
"val": 51
}]
$array // Your array
$result = [];
array_walk($array, function($object) use (&$result) {
$notExist = true;
foreach ($result as $item) {
if ($item->tax == $object->tax && $item->concept == $object->concept) {
$item->val += $object->val;
$notExist = false;
break;
}
}
if ($notExist) {
array_push($result, $object);
}
});
echo json_encode($result);
First group the objects:
$groups = [];
foreach($array as $object){
$groups[$object->tax . "\0" . $object->concept] = $object;
// I use the NUL byte to delimit, assuming it is absent in $tax and $concept
}
Then map each group into a summed-up object.
$output = array_map(function(array $group){
$object = new stdClass;
$object->tax = $group[0]->tax;
$object->concept = $group[0]->concept;
$object->val = array_reduce($group, function($carry, $item){
return $carry + $item->val;
}, 0);
return $object;
}, $groups);
<?php
$arr_str = '[
{"tax":"10", "concept":"TUC", "val":"10"},
{"tax":"10", "concept":"TUC", "val":"86"},
{"tax":"15", "concept":"TUC", "val":"8"},
{"tax":"11", "concept":"IPS", "val":"6"},
{"tax":"11", "concept":"IPS", "val":"45"}
]';
$arr = json_decode($arr_str);
$tmp_array = [];
foreach ($arr as $e) {
// combine "tax" and "concept" so we can use both of them as key. Use "_" as delimiter.
$key = $e->tax . "_" . $e->concept;
// sum the "val" if the key exists, otherwise assign it
isset($tmp_array[$key]) ? $tmp_array[$key] += $e->val : $tmp_array[$key] = $e->val;
}
$grouped_array = [];
foreach ($tmp_array as $k => $v) {
// ungroup the key so we can create an array like the original one
$tmp = explode("_", $k);
$grouped_array[] = (object)["tax" => $tmp[0], "concept" => $tmp[1], "val" => $v];
}
echo json_encode($grouped_array);
?>

Categories