PHP - Moving a key within an array and flatten it - php

I have this array of object:
[
{
"id": 1,
"name": "Carbo",
"menus": [
{
"id": 33,
"name": "FloralWhite",
"image": {
"web": "https://lorempixel.com/640/360/food/?89722",
"mobile": "https://lorempixel.com/640/360/food/?89722",
"square": "https://lorempixel.com/640/360/food/?89722"
},
"logs": {
"price": 2
}
},
{
"id": 40,
"name": "LightGray",
"image": {
"web": "https://lorempixel.com/640/360/food/?63930",
"mobile": "https://lorempixel.com/640/360/food/?63930",
"square": "https://lorempixel.com/640/360/food/?63930"
},
"logs": {
"price": 2
}
},
]
}
]
What I want to achieve:
[
{
"id": 1,
"name": "Carbo",
"menus": [
{
"id": 33,
"name": "FloralWhite",
"image": {
"web": "https://lorempixel.com/640/360/food/?89722",
"mobile": "https://lorempixel.com/640/360/food/?89722",
"square": "https://lorempixel.com/640/360/food/?89722"
},
"price": 2
},
{
"id": 40,
"name": "LightGray",
"image": {
"web": "https://lorempixel.com/640/360/food/?63930",
"mobile": "https://lorempixel.com/640/360/food/?63930",
"square": "https://lorempixel.com/640/360/food/?63930"
},
"price": 2
},
]
}
]
I've tried using laravel collection flatten with depth but it fail
$data = collect($data->menus);
$data = $data->flatten(1);
$data->values()->all();
How can I flatten the menus['logs'] object so it can one level with menu?

Something like this should do the trick. Simply iterate over your array, set the new property and remove the one you don't want.
$data = json_decode("[{
\"id\": 1,
\"name\": \"Carbo\",
\"menus\": [
{
\"id\": 33,
\"name\": \"FloralWhite\",
\"image\": {
\"web\": \"https://lorempixel.com/640/360/food/?89722\",
\"mobile\": \"https://lorempixel.com/640/360/food/?89722\",
\"square\": \"https://lorempixel.com/640/360/food/?89722\"
},
\"logs\": {
\"price\": 2
}
},
{
\"id\": 40,
\"name\": \"LightGray\",
\"image\": {
\"web\": \"https://lorempixel.com/640/360/food/?63930\",
\"mobile\": \"https://lorempixel.com/640/360/food/?63930\",
\"square\": \"https://lorempixel.com/640/360/food/?63930\"
},
\"logs\": {
\"price\": 2
}
}
]
}]");
foreach($data as $val){
foreach($val->menus as $menuVal){
$menuVal->price = $menuVal->logs->price;
unset($menuVal->logs);
}
}

#Stefen Suhat i really don't know what is the syntax for laravel but i did it with a simple php foreach() hope this will help you, as your array's depth is long so i had gone to all the levels of your array, check code and output snippet here https://eval.in/806879
try below one:
<?php
$array = array(
array(
"id"=> 1,
"name"=> "Carbo",
"menus"=> array(
array(
"id"=> 33,
"name"=> "FloralWhite",
"image"=> array(
"web"=> "https=>//lorempixel.com/640/360/food/?89722",
"mobile"=> "https=>//lorempixel.com/640/360/food/?89722",
"square"=> "https=>//lorempixel.com/640/360/food/?89722"
),
"logs"=> array(
"price"=> 2
)
),
array(
"id"=> 40,
"name"=> "LightGray",
"image"=> array(
"web"=> "https=>//lorempixel.com/640/360/food/?63930",
"mobile"=> "https=>//lorempixel.com/640/360/food/?63930",
"square"=> "https=>//lorempixel.com/640/360/food/?63930"
),
"logs"=> array(
"price"=> 2
)
),
)
)
);
foreach($array as $key => $value){
foreach ($value as $key1 => $value1) {
if(is_array($value1) && $key1 == "menus"){
foreach($value1 as $key2 => $value2) {
foreach ($value2 as $key3 => $value3) {
if(is_array($value3) && $key3 == "logs"){
unset($array[$key][$key1][$key2][$key3]);
$array[$key][$key1][$key2] = array_merge($array[$key][$key1][$key2], $value3);
}
}
}
}
}
}
echo "array after<br>";
echo "<pre>";
print_r($array); //your array after
?>

Related

merge all arrays with same title [duplicate]

This question already has answers here:
How to group subarrays by a column value?
(20 answers)
PHP - Group Array by its Sub Array Value (Indexed Array)
(1 answer)
Closed 6 months ago.
i have this array in php json.
i have made it to sort array by first Characther.
but now i'm stuck on how to merge the data under the same title.
my response now is.
[
{
"title": "A",
"data": {
"id": "317",
"name": "Aesethetica"
}
},
{
"title": "A",
"data": {
"id": "318",
"name": "Astonos"
}
},
{
"title": "B",
"data": {
"id": "320",
"name": "Bourjois"
}
},
{
"title": "B",
"data": {
"id": "321",
"name": "Bioderma"
}
}
]
i need to merge all data under each same title.
something like this:
[
{
"title": "A",
"data": [
{
"id": "317",
"name": "Aesethetica"
},
{
"id": "318",
"name": "Astonos"
}
]
},
{
"title": "B",
"data": [
{
"id": "320",
"name": "Bourjois"
},
{
"id": "321",
"name": "Bioderma"
}
]
}
]
kindly help.
Thanks
i got this now:
i made this update.. but still not the needed result.
this is my php code...
$result = [];
foreach ($data as $item) {
$firstLetter = substr($item['name'], 0, 1);
$result[] = [
'title' => $firstLetter = ctype_alnum($firstLetter) ? $firstLetter : '#',
'data' => $item
];
}
foreach ($result as $key => $item) {
$arr[$item['title']][$key] = $item;
}
and this is the result.
{
"A": [
{
"title": "A",
"data": {
"brand_id": "312",
"brand_name": "Adidsa"
}
},
{
"title": "A",
"data": {
"id": "314",
"name": "Adio"
}
},
still can't find make the needed response..
This is not perfomance optimized, but shows a simple solution.
Collect all data grouped by title, then reformat the array to your expected result.
$array = json_decode($json, true);
$collect = [];
foreach($array as $item) {
$collect[$item['title']][] = $item['data'];
}
ksort($collect);
$titles = [];
foreach($collect as $title => $data) {
$names = array_column($data, 'name');
array_multisort($names, SORT_ASC, SORT_STRING, $data);
$titles[] = ['title' => $title, 'data' => $data];
}
echo json_encode($titles, JSON_PRETTY_PRINT); results in
[
{
"title": "A",
"data": [
{
"id": "317",
"name": "Aesethetica"
},
{
"id": "318",
"name": "Astonos"
}
]
},
{
"title": "B",
"data": [
{
"id": "321",
"name": "Bioderma"
},
{
"id": "320",
"name": "Bourjois"
}
]
}
]

Loop through every occurrence of specific child key in a nested structure

I have this payload,
[
{
"id": 1,
"name": "T-Shirt",
"children_rec": [
{
"id": 2,
"name": "Classic",
"children_rec": [
{
"id": 3,
"name": "Lycra",
"children_rec": []
}
]
},
{
"id": 4,
"name": "Plain",
"children_rec": []
}
]
},
{
"id": 5,
"name": "Shirt",
"children_rec": [
{
"id": 6,
"name": "Plain",
"children_rec": []
}
]
}
]
I want to loop through every occurrence of children_rec.
What I have tried is,
foreach ($mainCategories as $category) {
if (!empty($category['children_rec'])) {
foreach ($category['children_rec'] as $child) {
if (!empty($category['children_rec'])) {
var_dump($child);
}
}
}
}
But this is not the dynamic way to achieve this. What if I have 5 or 6 level of childer_rec. How can I achieve this?
Edit
#ggorlen's way is cool, but What if I need this output?
[
{
"id": 1,
"name": "T-Shirt",
"children": [
"2",
"3",
"4"
]
},
{
"id": 5,
"name": "Shirt",
"children": [
"6"
]
}
]
Since you don't know the depth, you'll need a stack or recursion. Here's a solution with a stack:
<?php
$tree = json_decode('[ { "id": 1, "name": "T-Shirt", "children_rec": [ { "id": 2, "name": "Classic", "children_rec": [ { "id": 3, "name": "Lycra", "children_rec": [] } ] }, { "id": 4, "name": "Plain", "children_rec": [] } ] }, { "id": 5, "name": "Shirt", "children_rec": [ { "id": 6, "name": "Plain", "children_rec": [] } ] } ]', true);
for ($stack = $tree; !empty($stack);) {
$curr = array_pop($stack);
$flattened[] = $curr["name"]; // or just $curr if you only want the node
if (!empty($curr["children_rec"])) {
array_push($stack, ...$curr["children_rec"]);
}
}
print_r($flattened);
Array
(
[0] => Shirt
[1] => Plain
[2] => T-Shirt
[3] => Plain
[4] => Classic
[5] => Lycra
)
If order is important, you can array_reverse all arrays as you push them onto the stack without harming the linear time complexity.
For the updated specification, just plop the above code into a function and call it for each root node:
<?php
function flatten($tree) {
for ($stack = array_reverse($tree); !empty($stack);) {
$curr = array_pop($stack);
$flattened[] = $curr["id"];
if (!empty($curr["children_rec"])) {
array_push($stack, ...array_reverse($curr["children_rec"]));
}
}
return $flattened;
}
$tree = json_decode('[ { "id": 1, "name": "T-Shirt", "children_rec": [ { "id": 2, "name": "Classic", "children_rec": [ { "id": 3, "name": "Lycra", "children_rec": [] } ] }, { "id": 4, "name": "Plain", "children_rec": [] } ] }, { "id": 5, "name": "Shirt", "children_rec": [ { "id": 6, "name": "Plain", "children_rec": [] } ] } ]', true);
foreach ($tree as &$root) {
$root["children"] = flatten($root["children_rec"]);
unset($root["children_rec"]);
}
echo json_encode($tree, JSON_PRETTY_PRINT)."\n";
Output:
[
{
"id": 1,
"name": "T-Shirt",
"children": [
2,
3,
4
]
},
{
"id": 5,
"name": "Shirt",
"children": [
6
]
}
]

multidimensional array merge into one array if key is same without using nested loop

[
{
"status": true,
"data": [
{
"id": 2,
"name": "Algeria",
"country_code": "DZ",
"regions": [
{
"id": 2,
"country_id": 2,
"region_code": "RG01",
"depots": [
{
"id": 5,
"region_id": 2,
"depot_code": "DP04",
"depot_name": "North Depot",
"area": [
{
"id": 1,
"depot_id": 5,
"area_code": "AR1",
"area_name": "Area-1"
},
{
"id": 2,
"depot_id": 5,
"area_code": "AR2",
"area_name": "Area-2"
}
]
},
{
"id": 6,
"region_id": 2,
"depot_code": "DP06",
"depot_name": "east Depot",
"area": [
{
"id": 3,
"depot_id": 6,
"area_code": "AR3",
"area_name": "Area-3"
}
]
}
]
},
{
"id": 3,
"country_id": 2,
"region_code": "RG02",
"depots": []
}
]
}
]
}
]
i want to merge area into single array like
"area": [
{
"id": 1,
"depot_id": 5,
"area_code": "AR1",
"area_name": "Area-1"
},
{
"id": 2,
"depot_id": 5,
"area_code": "AR2",
"area_name": "Area-2"
},
{
"id": 3,
"depot_id": 6,
"area_code": "AR3",
"area_name": "Area-3"
}
]
i don't want to use multiple foreach.
thanks in advance.
You can use the following code to recursively iterate of all your structure and extract only data you need (by key). I assume $data has your original data structure and within $result you will get array of area:
$it = new RecursiveIteratorIterator(new RecursiveArrayIterator($data), RecursiveIteratorIterator::SELF_FIRST);
$result = [];
foreach ($it as $k => $v) {
if ($k === 'area') {
$result = array_merge($result, $v);
}
}
I would not overcomplicate things, loop through you data structure. Add all areas to a collection. Prepare your data structure and i added a check to secure there is no duplicates with unique().
$data = 'your-data';
$areas = collect();
foreach($data->data as $country) {
foreach($country->regions as $region) {
foreach ($region->depots as $depot) {
$areas->concat($depot->area);
}
}
}
$result = ['area' => $areas->unique('id')->all()];

Laravel : How do I return parent > child relationship from same table

I have a 3 tables product, category, attributes. In attributes table there is parent_id used for sub-attributes in a same table.Using loop I get a data.
My code :
$productDetails = Product::with('categories')->get();
foreach ($productDetails as $key => $value) {
foreach ($value->categories as $key => $value) {
$attributes = Attribute::where('product_id',$value->product_id)->where('category_id',$value->id)->where('parent_id',Null)->get();
$value->Attributes = $attributes;
foreach ($attributes as $key => $value) {
$subAttributes = Attribute::where('parent_id', $value->id)->get();
$value->subAttributes = $subAttributes;
}
}
}
Output :
{
"productDetails": [
{
"id": 1,
"title": "Small Size Diamond",
"icon": null,
"status": "Active",
"categories": [
{
"id": 1,
"product_id": 1,
"title": "Sieve Size",
"status": "Active",
"sort_order": 1,
"Attributes": [
{
"id": 1,
"product_id": 1,
"category_id": 1,
"parent_id": null,
"title": "- 2.0",
"status": "Active",
"sort_order": 1,
"subAttributes": [
[
{
"id": 9,
"product_id": 1,
"category_id": 1,
"parent_id": 1, // Attributes table ID
"title": "+ 0000 - 000",
"status": "Active",
"sort_order": 1
},
{
"id": 10,
"product_id": 1,
"category_id": 1,
"parent_id": 1, // Attributes table ID
"title": "+ 000 - 00",
"status": "Active",
"sort_order": 2
}
]
]
}
]
}
]
}
]}
The problem is in first product I gt completed response but in other prodcts in loop I do not get subAttributes data. How can i do this?
Simple, please do not use same variable name in all foreach loop,
Your code should like following
$productDetails = Product::with('categories')->get();
foreach ($productDetails as $pro_key => $pro_value) {
foreach ($pro_value->categories as $cat_key => $cat_value) {
$attributes = Attribute::where('product_id',$cat_value->product_id)->where('category_id',$cat_value->id)->where('parent_id',Null)->get();
$cat_value->Attributes = $attributes;
foreach ($attributes as $att_key => $att_value) {
$subAttributes = Attribute::where('parent_id', $att_value->id)->get();
$att_value->subAttributes = $subAttributes;
}
}
}

PHP: Add key value to the value of an existing key => value array

I have an array structured like so:
data: [
{
"category": "CAT555",
"products": {
"productID": 12345,
"sku": 3333
},
},
{
"category": "CAT1111",
"products": {
"productID: 12441,
"sku": 9999
},
}
]
If I have a new product I'd like to add to the CAT555 category? How would I do that?
Currently have this:
$key = array_search($categoryID, array_column($categories, 'categoryID'));
if ($key != false){
$categories[$key]['products'][] = [
'productID': '91232',
'sku': '52433'
];
But the result ends up looking like this:
data: [
{
"category": "CAT555",
"products":
"0": {
"productID": 12345,
"sku": 3333
}
},
{
"productID": 12345,
"sku": 3333
},
},
{
"category": "CAT1111",
"products": {
"productID: 12441,
"sku": 9999
},
}
]
Use the following approach with array_merge function:
$new_product = [
'productID' => '91232',
'sku' => '52433'
];
$search_key = 'CAT555';
foreach ($categories as $k => &$v) {
if ($v['category'] == $search_key) { // if the needed key is found
(isset($v['products'][0]))?
$v['products'].push($new_product)
: $v['products'] = array_merge([$v['products']], [$new_product]);
}
}
print_r($categories);

Categories