I have a JSON similar to the following:
{
"name": "Activities",
"description": "Activities",
"parent_group_id": 0,
"display": "Activities",
"group_id": 7,
"stamps": [
{
"stamp_id": 14,
"name": "Stamp 14",
"rank": 2
},
{
"stamp_id": 20,
"name": "Stamp 20",
"rank": 4
}
]
},
{
"name": "Games",
"description": "Games",
"parent_group_id": 0,
"display": "Games",
"group_id": 6,
"stamps": [
{
"stamp_id": 33,
"name": "Stamp 33",
"rank": 3
},
{
"stamp_id": 31,
"name": "Stamp 31",
"rank": 1
}
]
}
I want to get a list of each of the stamp_ids seperated by commas through PHP (eg. 14,20,33,31)
I have already tried this, with no luck:
$stampsdata = json_decode($stampsjson, true);
$numberofstamps = $stampsdata['stamps']['stamp_id']);
Can anyone help?
decode the JSON with json_decode and use array_column to get the IDs.
working solution:
// true needed to transform object to associative array
// $json contains your JSON string
$data = json_decode($json, true);
$stamps = [];
foreach ($data as $obj) {
$stamps[] = array_column($obj['stamps'], 'stamp_id');
}
// implode sub arrays and concatenate string
$str = '';
foreach ($stamps as $stamp) {
$sub = implode(',', $stamp);
$str .= $sub . ',';
}
// remove trailing comma
$stampIds = rtrim($str, ',');
print ($stampIds);
Related
I tried to parse a JSON using PHP from url. I need a list of item that have no children - means children field should be empty array and parent_id shouldn't be 0 - means not be parents.
JSON:
{
"body": {
"data": [
{
"id": 1,
"name": "car",
"parent_id": "0",
"children": [
{
"id": 2,
"name": "bmw",
"parent_id": "1",
"children": [
{
"id": 4,
"name": "bmw i8",
"parent_id": "2",
"children": []
}
]
},
{
"id": 3,
"name": "mustang",
"parent_id": "1",
"children": []
}
]
},
{
"id": 5,
"name": "clothes",
"parent_id": "0",
"children": []
},
{
"id": 6,
"name": "mobile",
"parent_id": "0",
"children": [
{
"id": 7,
"name": "apple",
"parent_id": "6",
"children": [
{
"id": 9,
"name": "Iphone 12 pro",
"parent_id": "7",
"children": []
},
{
"id": 10,
"name": "Iphone 11",
"parent_id": "7",
"children": []
}
]
},
{
"id": 8,
"name": "Xiaomi",
"parent_id": "6",
"children": []
}
]
}
]
}
}
Output Expected:
[4,3,9,10,8]
This is my php code that i tried and doesn't work.
$CategoryUrl = file_get_contents(self::CATEGORY_URL,true);
$array = json_decode($CategoryUrl,true);
$list = array();
foreach( $array['body']['data'] as $value ){
if (($value['parent_id'] != 0) && empty($value['children'])) {
foreach( $value['children'] as $val ){
$list[] = $val;
}
}
}
print_r($list);
It is indeed a little tricky to keep track of parent ID values and children call using array_walk_recursive as it jumps directly to its children. However, this can be still accomplished with your own recursive version like below. Keep checking with parent_id and children count. If both constraints satisfy, add them to $result, else keep calling children recursively.
<?php
$str = '{"body":{"data":[{"id":1,"name":"car","parent_id":"0","children":[{"id":2,"name":"bmw","parent_id":"1","children":[{"id":4,"name":"bmw i8","parent_id":"2","children":[]}]},{"id":3,"name":"mustang","parent_id":"1","children":[]}]},{"id":5,"name":"clothes","parent_id":"0","children":[]},{"id":6,"name":"mobile","parent_id":"0","children":[{"id":7,"name":"apple","parent_id":"6","children":[{"id":9,"name":"Iphone 12 pro","parent_id":"7","children":[]},{"id":10,"name":"Iphone 11","parent_id":"7","children":[]}]},{"id":8,"name":"Xiaomi","parent_id":"6","children":[]}]}]}}';
$data = json_decode($str,true);
$result = [];
function walkRecursive($data,&$result){
foreach($data as $entry){
if($entry['parent_id'] != 0 && count($entry['children']) == 0){
$result[] = $entry['id'];
}else{
walkRecursive($entry['children'],$result);
}
}
}
walkRecursive($data['body']['data'],$result);
print_r($result);
We can solve this problem by function call recursive algorithm,
hope it clear for you
$CategoryUrl = file_get_contents(self::CATEGORY_URL,true);
$array = json_decode($CategoryUrl, true);
$items = $array['body']['data'];
$list = [];
findParentIds(items, $list);
// doSomething
print_r($list);
/**
* passe by ref (list)
* #param array $children
* #param $list
*/
function findParentIds(array $children, & $list)
{
foreach ($children as $child) {
// use case 1: has no children and parent_id is 0 , just continue
if (empty($child['children']) && $child['parent_id'] == "0") {
continue;
}
// use case 2: has no children and parent_id is 0 , it's parent item
if (empty($child['children']) && $child['parent_id'] != "0") {
array_push($list, $child['id']);
}
// has children and parent_id is not 0 , recall function to treat use case 1 and 2 ..
findParentIds($child['children'], $list);
}
}
I want to add values from one array to another that are both potentially multidimensional when they have the same ID. Hard to explain so I added example.
arr1 => new structure, without full data
arr2 => old structure, with full data
Examples if you'd like to help out:
// arr1 (the correct structure/order, without the full data)
[{
"id": "24",
"children": [{
"id": "21",
"children": [{
"id": "15"
}]
}]
}]
// arr2 (full data, not in any specific order, may be nested)
[{
"id": "24",
"name": " x",
"time": "0",
"status": "0"
}, {
"id": "21",
"children": [{
"id": "15",
"name": "x",
"time": "0",
"status": "0"
}],
"name": "x",
"time": "0",
"status": "0"
}]
// arr3 (desired output for this example)
[{
"id": "24",
"children": [{
"id": "21",
"children": [{
"id": "15",
"name": "x",
"time": "0",
"status": "0"
}],
"name": "x",
"time": "0",
"status": "0"
}],
"name": " x",
"time": "0",
"status": "0"
}]
I tried this:
function merge($arr1, $arr2) {
foreach($arr1 as $key => $value){
foreach($arr2 as $value2) {
if($value['id'] === $value2['id']){
$arr1[$key]['name'] = $value2['name'];
$arr1[$key]['time'] = $value2['time'];
$arr1[$key]['status'] = $value2['status'];
if (is_array($value)) {
$arr1[$key]['children'] = merge($arr1, $arr2);
}
}
}
}
return $arr1;
}
to combine them, but I can't figure out how to handle the nesting correctly. I have tried a lot of other things as well like using array_merge_recursive() but it doesn't work because I want to merge based on ID value. Any help on getting me on track would be awesome thanks.
Current output for example:
[{
"id": "24",
"children": [{
"id": "21",
"children": [{
"id": "15"
}]
}],
"name": " x",
"time": "0",
"status": "0"
}]
Desired output for example:
[{
"id": "24",
"children": [{
"id": "21",
"children": [{
"id": "15",
"name": "x",
"time": "0",
"status": "0"
}],
"name": "x",
"time": "0",
"status": "0"
}],
"name": " x",
"time": "0",
"status": "0"
}]
Edit: How about this?
$detailsClean = [];
foreach($array2 as $item) {
$detailsClean = removeDepth($item, $detailsClean);
}
foreach($array1 as $itemKey => $item) {
$array1[$itemKey] = addDetails($item, $detailsClean);
}
function removeDepth($array, $result) {
$id = $array['id'];
if (!empty($array['children'])) {
foreach($array['children'] as $child) {
$result = removeDepth($child, $result);
}
unset($array['children']);
}
$result[$id] = $array;
return $result;
}
function addDetails($array, $details) {
$id = $array['id'];
if (isset($details[$id])) {
$array = array_merge($array, $details[$id]);
if (!empty($array['children'])) {
foreach($array['children'] as $childKey => $child) {
$array['children'][$childKey] = addDetails($child, $details);
}
}
}
return $array;
}
$array1 is updated with the final result.
Here is an example with the data from your unedited post: http://phpio.net/s/7z09
EDIT - I think I understand the problem now
From the example you gave, I realised the problem - your old array has all the data, but not the parent-child relationships, so you want to populate the new array (with the correct relationships) with the data form the old array. The problem here is that the merge function would have to fetch data from an arbitrary generation in the old array to populate the new array. This could mean a lot of looping.
So I think the solution is first to loop through the old data and flatten it - just have an associative array where the key is the "id" value. Then go through the new array and populate it from the flattened, "lookup" array. Does that make sense? In any case, you'd have two functions:
$lookUp = array();
//recursive function to flatten $arr2 into $lookUp array.
function indexOriginal($arr, &$lookUp) {
foreach($arr as $value) {
$lookUp[$value["id"]] = $value;
if (isset($value['children'])) {
unset($lookUp[$value["id"]]['children']);
indexOriginal($value['children'], $lookUp);
}
}
}
indexOriginal($arr2, $lookUp);
Then you populate the new array:
function fillInNew($arr, $lookUp) {
$return = array();
foreach($arr as $value) {
$newEntry = $lookUp[$value["id"]];
if (isset($value['children'])) $newEntry['children'] = fillInNew($value['children'], $lookUp);
$return[] = $newEntry;
}
return $return;
}
$newArr = fillInNew($arr1, $lookUp);
And $newArr should be what you're looking for
OLD USELESS STUFF FROM BEFORE:
This part of your code is weird to me:
if (is_array($value)) {
$arr1[$key]['children'] = merge($arr1, $arr2);
}
Obviously I may be completely confused, but don't you just need to put this?
if (isset($value2['children'])) $arr1[$key]['children'] = array_merge($arr1[$key]['children'], $value2['children']);
EDIT: I added array_merge because I saw that the 'children' array in the incomplete version could also need merging.
EDIT 2: now I've noticed that children can have further children (makes sense, I guess), which is why you had the correct idea of using the function recursively. You just seem to have passed in the wrong arrays - you want to pass in $arr1[$key]['children'] (as the incomplete array) and $value2['children'] (as the complete array)
function merge($arr1, $arr2) {
foreach($arr1 as $key => $value){
foreach($arr2 as $value2) {
if($value['id'] === $value2['id']){
$arr1[$key]['name'] = $value2['name'];
$arr1[$key]['time'] = $value2['time'];
$arr1[$key]['status'] = $value2['status'];
if (isset($value2['children'])) $arr1[$key]['children'] = merge($arr1[$key]['children'], $value2['children']);
}
}
}
return $arr1;
}
This question already has answers here:
PHP Array to JSON Array using json_encode(); [duplicate]
(4 answers)
Closed 5 years ago.
I tried real hard for my title to make sense haha. I have this JSON:
[{
"0": {
"id": 130427,
"created_at": 1512521776301,
"updated_at": 1512549188911,
"category": 0,
"platform": 6,
"date": 1513987200000,
"region": 8,
"y": 2017,
"m": 12,
"human": "2017-Dec-23",
"game": 76663
},
"2": {
"id": 131795,
"created_at": 1514172411633,
"updated_at": 1514190849639,
"category": 0,
"platform": 39,
"date": 1513987200000,
"region": 8,
"y": 2017,
"m": 12,
"human": "2017-Dec-23",
"game": 78658
}
}]
As you can see the position of the JSON object in the global json serves as the name of the object and I don't want this. This is what I want:
[{
"id": 130427,
"created_at": 1512521776301,
"updated_at": 1512549188911,
"category": 0,
"platform": 6,
"date": 1513987200000,
"region": 8,
"y": 2017,
"m": 12,
"human": "2017-Dec-23",
"game": 76663
},
{
"id": 131795,
"created_at": 1514172411633,
"updated_at": 1514190849639,
"category": 0,
"platform": 39,
"date": 1513987200000,
"region": 8,
"y": 2017,
"m": 12,
"human": "2017-Dec-23",
"game": 78658
}
]
I want the objects without a name. This is the code I'm using:
$json = file_get_contents('./releases.json');
$data = json_decode($json, TRUE);
$region = isset($_GET['region']) ? $_GET['region'] : null;
# if region is not null: ?region=8
if ($region) {
$region_filter = function($v) use ($region) {
// 8 == Worldwide
if ($v['region'] == $region || $v['region'] == 8) {
return true;
} else {
return false;
}
};
$data = array_filter($data['data'], $region_filter);
}
header('Content-Type: application/json');
echo json_encode(array($data)); // good
Thank you
You need to use array_values() to reindex the array.
PHP's json_encode() function will only produce an array if all array keys are numeric and don't have any gaps, e.g. 0, 1, 2, 3 etc. The problem is that array_filter() can remove certain keys and leave gaps, which causes json_encode() to include the keys as you show in your example. You can fix this by using array_values() to re-index the array before calling json_encode().
Here is an example:
<?php
// numeric array keys with no gaps
$a = ['a', 'b', 'c'];
echo json_encode($a);
// ["a","b","c"]
// filter out the 'b' element to introduce a gap in the keys
$a = array_filter($a, function ($v) {
return $v !== 'b';
});
echo json_encode($a);
// {"0":"a","2":"c"}
// re-index the array to remove gaps
$a = array_values($a);
echo json_encode($a);
// ["a","c"]
Solution
To get total price from loop in json we need to use $tot += +$data['price'].","; in below code
$arr = '[{
"id": 1,
"name": "A green door",
"price": 11,
"tags": ["home", "green"]
},
{
"id": 2,
"name": "A green door",
"price": 15,
"tags": ["home", "green"]
},
{
"id": 3,
"name": "A green door",
"price": 10,
"tags": ["home", "green"]
}]';
//print_r($arr);
$arr = json_decode($arr,TRUE);
foreach ($arr as $data)
{
$tot += +$data['price'].",";
}
echo "Total = ".rtrim($tot,',');
Use this,
$arr = json_decode($arr,TRUE);
echo "Total = ".array_sum(array_column($arr,"price"));
array_sum - Calculate the sum of values in an array
array_column - Return the values from a single column in the input array
Give it a try, this will work.
$arr = json_decode($arr,TRUE);
foreach ($arr as $data)
{
$tot[] =$data['price'];
}
echo "Total=".array_sum($tot);
How do I get all of the keys and loop through them, echoing each one, from a JSON object array?
Here is my code:
/* SAMPLE JSON THAT IS SENT
$mystring = '{
"display_name": "Silverware",
"fields": [
{
"field_name": "Age",
"sort_order": 1,
"required": 0,
"view_type": "text",
"description": "",
"multi_value": 0,
"char_count": 255
},
{
"field_name": "Brand",
"sort_order": 2,
"required": 0,
"view_type": "multiselect",
"description": "",
"multi_value": 1,
"char_count": 255
}
]
}';
*/
$json = json_decode($HTTP_RAW_POST_DATA);
$arr = $json->{'fields'};
// This is how I print a specific value
//print $arr[0]->{'field_name'};
Adding the following isn't working for me:
foreach ($arr as $k => $v) {
echo $k', ';
}
Use true for the second parameter of json_decode().
foreach ($j['fields'] as $field) {
$keys = array_keys($field);
foreach ($keys as $key) {
echo $key;
}
}