I have a json tree with categories,
I would like to obtain the last level of elements for each different category.
For example on this json:
[
{
"category_id": "3",
"parent_id": "2",
"name": "Women",
"categories": [
{
"category_id": "11",
"parent_id": "3",
"name": "Clothing",
"categories": [
{
"category_id": "30",
"parent_id": "11",
"name": "T-shirts",
"categories": null
},
{
"category_id": "33",
"parent_id": "11",
"name": "jeans",
"categories": null
}
]
}
]
},
{
"category_id": "5",
"parent_id": "2",
"name": "Footwear ",
"categories": [
{
"category_id": "15",
"parent_id": "5",
"name": "Rings",
"categories": [
{
"category_id": "51",
"parent_id": "15",
"name": "Small Leathers",
"categories": null
}
]
},
{
"category_id": "16",
"parent_id": "5",
"name": "Bands",
"categories": [
{
"category_id": "41",
"parent_id": "16",
"name": "boots",
"categories": null
}
]
},
{
"category_id": "48",
"parent_id": "5",
"name": "Bracelets",
"categories": [
{
"category_id": "55",
"parent_id": "48",
"name": "Cocktail",
"categories": null
}
]
}
]
}
]
The result would be an array (T-shirts, Jeans, Small Leathers, boots, cocktail)
What I was thinking is to decode it on an array and search filter the array with all the categories that are null, but I'm not sure if it's the best option because the object have different levels.
(I'm sorry for the English)
Json string is not a valid. It can be made valid by enclosing the json string in {}.
$json = '{"categories": [
{
"category_id": "3",
"parent_id": "2",
"name": "Women",
"categories": [
{
"category_id": "11",
"parent_id": "3",
"name": "Clothing",
"categories": [
{
"category_id": "30",
"parent_id": "11",
"name": "T-shirts",
"categories": null
},
{
"category_id": "33",
"parent_id": "11",
"name": "jeans",
"categories": null
}
]
}
]
},
{
"category_id": "5",
"parent_id": "2",
"name": "Footwear ",
"categories": [
{
"category_id": "15",
"parent_id": "5",
"name": "Rings",
"categories": [
{
"category_id": "51",
"parent_id": "15",
"name": "Small Leathers",
"categories": null
}
]
},
{
"category_id": "16",
"parent_id": "5",
"name": "Bands",
"categories": [
{
"category_id": "41",
"parent_id": "16",
"name": "boots",
"categories": null
}
]
},
{
"category_id": "48",
"parent_id": "5",
"name": "Bracelets",
"categories": [
{
"category_id": "55",
"parent_id": "48",
"name": "Cocktail",
"categories": null
}
]
}
]
}
]}';
Decode the json string in to php opject
$json_object = json_decode($json);
Use this recursive function to fetch get all the last level categories in a array.
function getLastCategories($object){
$last_categories = array();
if(is_array($object->categories)){
foreach($object->categories as $categories){
$last_categories = array_merge( $last_categories, getLastCategories($categories));
}
}else{
$last_categories[]=$object->name;
}
return $last_categories;
}
print_r(getLastCategories($json_object));
Output:
Array
(
[0] => T-shirts
[1] => jeans
[2] => Small Leathers
[3] => boots
[4] => Cocktail
)
You can do this using recursive iterators.
$categories = json_decode($json);
// create the iterator
$iterator = new RecursiveIteratorIterator(new RecursiveArrayIterator($categories));
// iterate recursively
foreach ($iterator as $key => $subcategories) {
// if the 'categories' key is empty for the current level...
if ($key == 'categories' && !$subcategories) {
// then add the value of the 'name' key for the current level to your result array.
$result[] = $iterator->getSubIterator()->offsetGet('name');
}
}
This may not be the most efficient way to do it, but it makes the code pretty simple.
Related
I'm struggling to remove item from recursive array if parent id don't match. All I want to display separate tree for each tree number. I didn't find any solution with SQL so now I am retrieving top nodes of that tree number and removing array those items don't have that top node ids. I already have tree structure, below I'm providing the structure of array.
{
"196": {
"id": "196",
"username": "test1",
"parent_id": null,
"children": [
{
"id": "197",
"parent_id": "196",
"flower_id": null,
"username": "test1",
"children": []
},
{
"id": "198",
"parent_id": "196",
"flower_id": "1690587",
"username": "test3",
"children": [
{
"id": "213",
"parent_id": "198",
"flower_id": "5197062",
"username": "test33",
"children": []
}
]
},
{
"id": "199",
"parent_id": "196",
"flower_id": "1690587",
"username": "test2",
"children": [
{
"id": "205",
"parent_id": "199",
"flower_id": null,
"username": null,
"children": [
{
"id": "207",
"parent_id": "205",
"flower_id": null,
"username": null,
"children": []
}
]
},
{
"id": "212",
"parent_id": "199",
"flower_id": "6794158",
"username": "gunu",
"children": []
}
]
}
]
}
}
Here is what I'm doing doing
function recursive_unset(&$array, $parentIds = array()) {
foreach ($array as $key => &$value) {
if(!in_array($value['parent_id'], $parentIds)) {
unset($array[$key]);
}
if (is_array($value['children'])) {
$this->recursive_unset($value, $parentIds);
}
}
}
This is how I'm calling this function $data = $this->recursive_unset($array, [198,199]);
Any help is appreciated.
Thanks in advance.
I'm retrieving data from a database and pushing it to arrays then use json_encode() to output in json format. I have ended up having the data in this format.
[
{
"category_id": "1",
"category_name": "Construction Materials"
},
{
"items": [
{
"id": "1",
"item_name": "Wire Mesh",
"price": "459",
"image_url": null
},
{
"id": "2",
"item_name": "Cement",
"price": "700",
"image_url": null
},
{
"id": "3",
"item_name": "Barbed Wire",
"price": "3000",
"image_url": null
},
{
"id": "4",
"item_name": "Iron sheet",
"price": "200",
"image_url": null
}
]
},
{
"category_id": "2",
"category_name": "Plumbing"
},
Here is what I want to achieve:
[
{
"category_id": "1",
"category_name": "Construction Materials"
"items": [
{
"id": "1",
"item_name": "Wire Mesh",
"price": "459",
"image_url": null
},
{
"id": "2",
"item_name": "Cement",
"price": "40",
"image_url": null
},
{
"id": "3",
"item_name": "Barbed Wire",
"price": "3000",
"image_url": null
},
{
"id": "4",
"item_name": "Iron sheet",
"price": "200",
"image_url": null
}
]
},
{
"category_id": "2",
"category_name": "Plumbing"
},
How can I achive this in php. Is it possible to edit the contents of the main array? how can I add "items" after "category_name"
Regards..
$array = json_decode($yourJson);
$arrayLength = count($array);
$finalArray = [];
for ($i=0; $i < $arrayLength; $i+=2) {
$finalArray[] = $array[$i] + $array[$i + 1];
}
$backToJson = json_encode($finalArray);
Alternative to Mattijs's answer.
function get_first_property($object) {
$properties = array_keys(get_object_vars($object));
return reset($properties);
}
function object_merge($object1, $object2) {
return (object) array_merge((array) $object1, (array) $object2);
}
// loop through each of the array objects
$previous_first_property = null;
foreach ($array as $i => $object) {
$first_property = get_first_property($object);
// merge if the 1st property is "items", and the previous 1st was "category_id"
if ($first_property == "items" && $previous_first_property == "category_id") {
$array[$i - 1] = object_merge($array[$i - 1], $array[$i]);
unset($array[$i]);
}
$previous_first_property = $first_property;
}
I have a list of (the result of a query in DB) like this:
[
{
"id": "1",
"parent_id": null,
"title": "مدادنوکی",
"url": "/medadnoki"
},
{
"id": "2",
"parent_id": null,
"title": "جامعه",
"url": "/commiunity"
},
{
"id": "5",
"parent_id": "1",
"title": "درباره ی مدادنوکی",
"url": "/about"
},
{
"id": "6",
"parent_id": "1",
"title": "درباره ی مدادنوکی",
"url": "/about"
},
{
"id": "7",
"parent_id": "2",
"title": "همکاران",
"url": "/co-worker"
},
{
"id": "8",
"parent_id": "2",
"title": "اساتید",
"url": "/masters"
}
]
But I want to create an object like this:
[
{
"title": "مدادنوکی",
"url": "/medadnoki",
"subs" : [
{
"title": "درباره مدادنوکی",
"url": "/about"
},
{
"title": "درباره مدادنوکی",
"url": "/about"
},
{
"title": "درباره مدادنوکی",
"url": "/about"
},
{
"title": "درباره مدادنوکی",
"url": "/about"
}
]
},
{
"title": "جامعه",
"url": "/soc",
"subs" : [
{
"title": "همکاران",
"url": "/co-work"
},
{
"title": "اساتید",
"url": "/masters"
}
]
}
]
I have handled this process with two foreach in php and it means I process data twice and it is not efficient and will be slow.
Is there any Idea to doing this with just one foreach?
using one foreach means faster than two foreach twice and It will show the result in big data
Assuming you have the results in an order where the parents appear in the results before any children they may have, this should work:
$nested = [];
foreach($results as $r) {
if($r['parent_id'] === null) {
$nested[$r['id']] = [
'title' => $r['title'],
'url' => $r['url'],
'subs' => []
];
continue;
}
$nested[$r['parent_id']]['subs'][] = [
'title' => $r['title'],
'url' => $r['url']
];
}
$nested = array_values($nested);
I've been struggling around this for a while now and can't seem to get the right algorithm.
What I want is to sort this:
$variable = '{
"0": {
"id": "0",
"code": "main_colour",
"label": "Main Colour",
"options": [{
"id": "825",
"label": "White",
"products": ["1", "2", "3"]
}, {
"id": "840",
"label": "Cream",
"products": ["3", "4", "5"]
}],
"position": "0"
},
"2": {
"id": "0",
"code": "size",
"label": "Size",
"options": [{
"id": "825",
"label": "S",
"products": ["1", "2", "3"]
}, {
"id": "840",
"label": "M",
"products": ["3", "4", "5"]
}],
"position": "0"
}
}';
And the output would be
$variable = '{
"0": {
"id": "0",
"code": "main_colour",
"label": "Main Colour",
"options": [{
"id": "840",
"label": "Cream",
"products": ["3", "4", "5"]
},{
"id": "825",
"label": "White",
"products": ["1", "2", "3"]
}],
"position": "0"
},
"2": {
"id": "0",
"code": "size",
"label": "Size",
"options": [{
"id": "840",
"label": "M",
"products": ["3", "4", "5"]
}, {
"id": "825",
"label": "S",
"products": ["1", "2", "3"]
}],
"position": "0"
}
}';
So basically it should be sorted using the label inside the "options" without affecting the other fields. I've been trying usort and tried different algorithms but to no avail.
Current code that sorts only the outside "label" and not the inner label:
function optionsSort($a, $b) {
return strcmp($a['options'][0]['label'], $b['options'][0]['options']['label']);
}
usort($variable, "optionsSort"));
Here's the code:
// your array
$variable = '{
"0": {
"id": "0",
"code": "main_colour",
"label": "Main Colour",
"options": [{
"id": "825",
"label": "White",
"products": ["1", "2", "3"]
}, {
"id": "840",
"label": "Cream",
"products": ["3", "4", "5"]
}],
"position": "0"
},
"2": {
"id": "0",
"code": "size",
"label": "Size",
"options": [{
"id": "825",
"label": "S",
"products": ["1", "2", "3"]
}, {
"id": "840",
"label": "M",
"products": ["3", "4", "5"]
}],
"position": "0"
}
}';
$a = json_decode($variable);
foreach ($a as $item) {
// sorting function
usort($item->options, function($a, $b) { return strcmp($a->label, $b->label); });
}
My response code :
Shpping : [
{
"id": "1",
"name": "Dress",
"deleted_at": null,
"created_at": null,
"updated_at": null,
"minicomp": [
{
"id": "1",
"cname": "basic",
"base_id": 44
},
{
"id": "2",
"cname": "Shirt",
"base_id": 177444
},
{
"id": "3",
"cname": "Pants",
"base_id": 444
}
]
}
];
I want to access base_id of of every object in child array 'minicomp' whose parent is 'Shipping'. How can I access it?
First convert your json into array using json_decode().Like this..
$json =<your json>;
$array = json_decode($json,true);
Then
echo $array['Shpping '][0]]['minicomp'][0]['id'];//outputs 1
Example:
<?php
$json = '[{
"id": "1",
"name": "Dress",
"deleted_at": null,
"created_at": null,
"updated_at": null,
"minicomp": [{
"id": "1",
"cname": "basic",
"base_id": 44
}, {
"id": "2",
"cname": "Shirt",
"base_id": 177444
}, {
"id": "3",
"cname": "Pants",
"base_id": 444
}]
}]';
$array = json_decode($json,true);
//print_r($array);
$minicomp = $array[0]['minicomp'];
echo $minicomp[0]['id'];
echo $minicomp[1]['id'];
?>
UPDATE
For getting all ids.Without defining indexes.Use foreach loop:
foreach($minicomp as $key=>$value){
echo $minicomp[$key]['id']."<br/>";
}